Error Handling
The openpine_vm::Error enum covers both compile-time and runtime errors.
Error Types
rust
pub enum Error {
Compile(CompileErrors), // Parse, type-check, or compile errors
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
Exception(Exception), // Runtime exception (e.g. runtime.error())
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
eprintln!("{}", errors);
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!("Init exception: {}", 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)) => {
// CompileErrors implements Display
// Shows formatted errors with line/column numbers
eprintln!("{}", errors);
}
_ => {}
}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
eprintln!("{}", exception.display());
// Get the source span of the error
if let Some(span) = exception.first_span() {
eprintln!(" at line {}", span.start.line);
}
}
_ => {}
}Compilation Warnings
Warnings don't prevent execution but indicate potential issues:
rust
let instance = Instance::builder(source, tf, "NASDAQ:AAPL").build().await?;
for warning in instance.warnings() {
eprintln!("Warning: {}", warning.display_as_warning());
}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 — Pine Script 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
use std::pin::pin;
use futures_util::StreamExt;
async fn run_safely(
instance: &mut Instance,
symbol: &str,
timeframe: TimeFrame,
) -> Result<(), Error> {
for w in instance.warnings() {
eprintln!("[warn] {}", w.display_as_warning());
}
let mut stream = pin!(instance.run(symbol, timeframe));
while let Some(result) = stream.next().await {
match result? {
Event::Log(log) => {
eprintln!("[{:?}] {}", log.level, log.message);
}
Event::Alert(alert) => {
println!("Alert: {}", alert.message);
}
_ => {}
}
}
Ok(())
}Next Steps
- C/C++ API — embed OpenPine in C++ projects
- LSP & Editor Support — language server features