Error handling
The entry point analyze returns Result<FuncSpace, MetricsError>.
This page documents what each variant means and how to act on it.
Heads up.
MetricsErroris#[non_exhaustive], so always include a_arm when matching exhaustively to stay forward-compatible with future variants.
Pattern-matching the error variants
use big_code_analysis::{analyze, LANG, MetricsError, MetricsOptions, Source}; fn main() { let result = analyze( Source::new(LANG::Rust, b"this is not rust") .with_name(Some("snippet.rs".to_owned())), MetricsOptions::default(), ); match result { Ok(space) => println!("ok: {} lines", space.metrics.loc.sloc()), Err(MetricsError::EmptyRoot) => { eprintln!("walker produced no top-level FuncSpace"); } Err(MetricsError::LanguageDisabled(lang)) => { eprintln!("language {:?} is not enabled in this build", lang); } // `MetricsError` is `#[non_exhaustive]`; new variants may be added. Err(_) => eprintln!("unexpected MetricsError variant"), } }
What each variant means
EmptyRoot— Reserved; not produced today.metrics_with_optionsalways pushes a synthetic top-levelUnitFuncSpacebefore walking the AST, so every parse — including empty, whitespace-only, and comment-only input — returnsOk(FuncSpace { kind: Unit, .. }). The variant is kept for a future walker change that could let the state stack legitimately drain to empty.LanguageDisabled(LANG)— The requestedLANGis not enabled in this build. Every dispatch entry point produces it when the caller selects aLANGwhose per-language Cargo feature is off. The default feature set (all-languages) compiles every grammar in, so you only see this variant after opting into a narrower set (--no-default-features --features rust,…).
MetricsError has no ParseHasErrors or NonUtf8Path variant;
since it stays #[non_exhaustive], a future strict-parsing or
strict-identifier mode can introduce them without a breaking
change. Non-UTF-8 paths are already handled up front: the
recommended analyze entry point takes a caller-supplied
Source::name (Option<String>), so a lossy path is never
round-tripped in the first place.
Tree-sitter does not always say "no"
Most parse errors do not surface as Err(_). Tree-sitter is an
error-recovering parser — it will produce a tree even for
syntactically broken input, marking the bad regions with ERROR
nodes. The metric walk happily computes numbers over the recovered
tree. That means:
- Garbage in, numbers out. Feeding C++ source to
LANG::Pythongenerally produces anOk(FuncSpace)whose metrics are nonsense. Make sure you have selected the right language (e.g. viaguess_language) before trusting the result. - Partial files score. A truncated file with an unterminated
brace will still return
Ok(FuncSpace). The metrics reflect the recovered tree, not the intended source.
If you need to know whether the input parsed cleanly, count
ERROR nodes by walking the tree-sitter AST yourself (see the
Node escape hatch in
STABILITY.md) or use
bca find -t ERROR on the CLI side (see the
Nodes page).
Bubbling MetricsError through ?
Because MetricsError implements [std::error::Error], you can
bubble it through any Result<_, Box<dyn Error>> chain without
boilerplate:
#![allow(unused)] fn main() { use std::error::Error; use big_code_analysis::{analyze, FuncSpace, LANG, MetricsOptions, Source}; pub fn run( lang: LANG, source: &[u8], name: Option<String>, ) -> Result<FuncSpace, Box<dyn Error>> { Ok(analyze( Source::new(lang, source).with_name(name), MetricsOptions::default(), )?) } }
If you want a project-specific error type, an explicit From impl
keeps call sites clean while letting you attach extra context
(file path, language guess, etc.).
Warnings are not errors
The library writes warnings to stderr for non-fatal issues
(malformed bca: suppression markers, mainly). They do not abort
the walk and they do not flip Ok to Err. If you are running
embedded inside a server or library and need to capture those
warnings, redirect stderr at the process level — the library does
not currently expose a programmatic warning sink.