Error Handling
The navi_vm::Error enum covers both compile-time and runtime errors.
Error Types
rust
pub enum Error {
Compile(CompileErrors), // Parse, type-check, or compile errors
Exception(RuntimeError), // Runtime exception (e.g. runtime.error())
MissingScriptType, // No indicator()/strategy()/library() call
InputValueNotFound(usize), // Invalid input ID in with_input_value
SetInputValue(usize, String), // Type mismatch for input value
UnsupportedTimeFrame(TimeFrame), // Script doesn't support this timeframe
SessionNotAllowed(TradeSession), // Session type not enabled
DataProvider(String), // Error from the DataProvider
LibraryScriptNotExecutable, // Tried to execute a library
}Handling Errors
Pattern Matching
rust
async fn run(source: &str) {
let mut instance = match Instance::builder(source, TimeFrame::days(1), "NASDAQ:AAPL")
.build().await
{
Ok(inst) => inst,
Err(Error::Compile(errors)) => {
// Display compile errors with source locations (colorized)
eprintln!("{}", errors.display());
return;
}
Err(Error::MissingScriptType) => {
eprintln!("Script must call indicator(), strategy(), or library()");
return;
}
Err(Error::Exception(exception)) => {
// Global-scope runtime error (e.g., runtime.error() at top level)
eprintln!("{}", exception.display());
return;
}
Err(e) => {
eprintln!("Build error: {}", e);
return;
}
};
// Run
match instance.run_to_end("NASDAQ:AAPL", TimeFrame::days(1)).await {
Ok(()) => {}
Err(Error::Exception(exception)) => {
eprintln!("Runtime exception: {}", exception.display());
}
Err(e) => {
eprintln!("Execution error: {}", e);
}
}
}Compile Errors
Compile errors include source spans for precise error reporting:
rust
match Instance::builder(source, tf, "NASDAQ:AAPL").build().await {
Err(Error::Compile(errors)) => {
// Render all diagnostics with codespan-reporting (colorized)
eprintln!("{}", errors.display());
// Or plain text (no ANSI colors)
eprintln!("{}", errors.display().set_colorize(false));
// Access individual diagnostics
for diag in errors.diagnostics() {
eprintln!(" {}", diag.message);
}
}
_ => {}
}Runtime Exceptions
Runtime exceptions occur during script execution (e.g., runtime.error() calls, index out of bounds):
rust
match instance.run_to_end("NASDAQ:AAPL", TimeFrame::days(1)).await {
Err(Error::Exception(exception)) => {
// Display the exception with source file context and backtrace
eprintln!("{}", exception.display());
// Access the error span directly
if let Some(span) = exception.spans.first() {
eprintln!(" at line {}", span.start.line);
}
}
_ => {}
}Compilation Warnings
Warnings don't prevent execution but indicate potential issues. Instance::warnings() returns a Warnings value bundled with source files, so you can render them directly:
rust
let instance = Instance::builder(source, tf, "NASDAQ:AAPL").build().await?;
let warnings = instance.warnings();
if !warnings.is_empty() {
// Render as yellow warnings with codespan-reporting
eprintln!("{}", warnings.display());
}Warnings are also emitted as Event::Warning in the event stream from run():
rust
let mut handle = instance.run(symbol, timeframe);
while let Some(result) = handle.next_event().await {
match result? {
Event::Warning(warnings) => {
eprintln!("{}", warnings.display());
}
_ => {}
}
}Best Practices
- Always handle compile errors — show them to the user with source context
- Handle exceptions from
build()too —build()executes the global scope to discover script metadata (indicator(),input.*(), etc.), so any runtime error in top-level code (e.g.,runtime.error(), invalid function arguments) will surface asError::Exceptionbefore execution even begins - Stop execution on runtime errors — Navi computes bar-by-bar with each bar depending on the previous bar's state (
varvariables, series history likeclose[1], etc.). If one bar fails, all subsequent results would be invalid, so you should stop on error - Process events from the stream — log events can contain useful diagnostic info; consume the stream from
run()or userun_to_end()to discard events - Check warnings after build — they often indicate deprecated features or potential bugs
rust
async fn run_safely(
instance: &mut Instance,
symbol: &str,
timeframe: TimeFrame,
) -> Result<(), Error> {
let warnings = instance.warnings();
if !warnings.is_empty() {
eprintln!("{}", warnings.display());
}
let mut handle = instance.run(symbol, timeframe);
while let Some(result) = handle.next_event().await {
match result? {
Event::Log(log) => {
eprintln!("[{:?}] {}", log.level, log.message);
}
Event::Alert(alert) => {
println!("Alert: {}", alert.message);
}
_ => {}
}
}
Ok(())
}Next Steps
- LSP & Editor Support — language server features