---
title: Error handling in Substrate runtime
tags: parity, FRAME, substrate
---
### StackExchange question
**What should a Substrate developer consider when handling errors in the runtime?**
The [substrate docs](https://docs.substrate.io/build/events-and-errors) mention that all the runtime errors should be gracefully handled:
> Runtime code should explicitly and gracefully handle all error cases. Functions in the runtime code must be non-throwing functions that never cause the compiler to panic.
What are the consequences and side-effects of error panics in the runtime? Could you elaborate based on the Substrate codebase?
### Answer
The main principles for FRAME developers when handling errors in the runtime are:
1. **Extrinsics**: Any logic path reached by an account must not panic (usually any extrinsict). If an extrinsic panics, the runtime may be vulnerable to DoS attacks, as bad actors may call an unlimited amount of extrinsics without paying fees.
2. **Inherents**: Inherents (e.g. timestamp) may panic without affecting security of the chain.
3. **Hooks**: `on_initialize` and `on_finalize` hooks should never panic. In this case, the chain may become dysfunctional and stop processing blocks. It is important to ensure that the logic in the pallet hook's is infallible (all hooks?).
4. **Off-chain workers**: Offchain workers can panic without affecting the runtime.
5. **Other non-runtime logic**: Tests and benchmarks can panics.
Now, let's look at why those principles hold true.
### Extrinsics
The extrinsic lifetime is managed by something that implements the `ExecuteBlock` trait (below). The `fn ExecuteBlock::execute_block` method is called with the block to execute, which contains a set of
from `frame_support/traits/misc.rs.`
```rust=
/// Something that can execute a given block.
///
/// Executing a block means that all extrinsics in a given block will be executed and the resulting
/// header will be checked against the header of the given block.
pub trait ExecuteBlock<Block: BlockT> {
/// Execute the given `block`.
///
/// This will execute all extrinsics in the block and check that the resulting header is
/// correct.
///
/// # Panic
///
/// Panics when an extrinsics panics or the resulting header doesn't match the expected header.
fn execute_block(block: Block);
}
```
### Inherents
[Inherent transactions](https://docs.substrate.io/fundamentals/transaction-types/#inherent-transactions) are unsigned transactions are added by block authoring nodes directly without requiring the callable to be gossiped and added to transaction pools. An example of an inherent is the `fn set` inherent in the [`pallet-timestamp`](https://docs.rs/pallet-timestamp/latest/pallet_timestamp/).
### Hooks
### OCW
### Non-runtime logic
---
---
`draft, answer points`
- code in extrinsic should never panic. This could allow attackers to DoS the runtime and/or negatively affect the state of the chain.
- logic in [pallet hooks](https://paritytech.github.io/substrate/master/frame_support/traits/trait.Hooks.html) should never panic, as it could halt the chain. Hooks should be infallible
- non-runtime code (benchmarking, tests) can fail with panics as the logic won't be considered when compiling the runtime binary.
> can GenesisBuild panic?
> e.g. https://github.com/paritytech/substrate/pull/12549/files#diff-194656be9ce9133b248a5b7cd18842eb5d3faacde3f1221b32e654419870136aR724
Expand on:
- offchain worker can panic
- tx path that can be reached by any account must not panic, anything else is fine (see timestamp)