This week, we worked on improving the developer experience using Apibara from the command line. The Apibara CLI and Sinks' latest release comes with improved error messages.
For example, trying to execute the apibara run
command with non-existing files
results in the following error message. This message provides enough context to
help you debug the error. If you feel stuck, you can always post the error in
our Discord, and we will do our best to help you.
$ apibara run path/to/indexer.ts# Error: cli operation failed# ├╴at cli/src/run.rs:36:64# │# ╰─▶ failed to load script# ├╴at sinks/sink-common/src/cli.rs:34:14# ╰╴script file not found: path/to/indexer.ts
The CLI will warn you if the indexer doesn't export the config or transform function or if any key was misspelt.
$ apibara run indexer.js# sink configuration error# ├╴at /tmp/nix-build-apibara-0.0.0.drv-0/source/sinks/sink-common/src/lib.rs:75:10# ├╴invalid sink options# │# ╰─▶ webhook sink operation failed# ├╴at sinks/sink-webhook/src/configuration.rs:49:14# ╰╴missing target url
One challenge when running Apibara integrations in production is figuring out if
the indexer exited because of a configuration error or because of a transient
error. This is important to decide whether to restart the indexer or not. This
release helps operators by returning a different Unix exit code based on the
error type. These follow the codes defined in the sysexit.h
header.
0
: the indexer was interrupted and exited successfully.78
: configuration error. The indexer should not be restarted.75
: temporary error. The indexer should be restarted after a back-off period.error-stack
crateWe improved error handling by changing how we manage errors in the Apibara
source code. Before this release, Apibara implemented errors following Rust best
practices with libraries exporting one or more error types implemented using
thiserror
and applications using eyre
. This approach worked well initially,
but thiserror encourages reusing the same variant for errors of the same type
(e.g. MyError::Io(std::io::Error)
for io errors). Any context of what
operation caused the error is lost, resulting in error messages not helping
users fix their bugs.
Error-stack approach is a hybrid between thiserror and eyre (or anyhow). Like thiserror, libraries and applications should define their error type. This can be anything. In Apibara, we use both structs and enums. Like eyre, it's possible to attach additional context to errors to provide more information to end users.
pub fn load_script(path: &str, options: ScriptOptions) -> Result<Script, LoadScriptError> { let Ok(_) = fs::metadata(path) else { return Err(LoadScriptError) .attach_printable_lazy(|| format!("script file not found: {path:?}") ); }; let current_dir = std::env::current_dir() .change_context(LoadScriptError) .attach_printable("failed to get current directory")?; let script = Script::from_file(path, current_dir, options) .change_context(LoadScriptError) .attach_printable_lazy(|| format!("failed to load script at path: {path:?}") )?; Ok(script)}
This change is only the first step in a better developer experience. You should expect more improvements in the following weeks and months.
Apibara is the fastest platform to build production-grade indexers that connect onchain data to web2 services.
Resources