newt_data/error.rs
1//! Error type for the Phase 21 `newt-data` engine.
2//!
3//! See [`docs/design/centaur-data-scientist.md`](../../../docs/design/centaur-data-scientist.md):
4//! the engine is headless and surfaces every failure as a typed [`DataError`]
5//! so the later MCP adapter (step 21.2) and PyO3 submodule (step 21.6) can map
6//! each variant to an honest, machine-readable error without string-sniffing.
7
8use thiserror::Error;
9
10/// Everything that can go wrong inside the `newt-data` SQLite engine.
11///
12/// The three `#[from]` variants wrap the upstream errors verbatim so the
13/// underlying cause is never lost; the remaining variants are the engine's own
14/// invariant violations (Phase 21 — identifier safety, table existence, and
15/// the empty-CSV guard described in
16/// [`docs/design/centaur-data-scientist.md`](../../../docs/design/centaur-data-scientist.md)).
17#[derive(Debug, Error)]
18pub enum DataError {
19 /// A SQLite operation failed (open, pragma, prepare, step, bind, …).
20 #[error("sqlite error: {0}")]
21 Sqlite(#[from] rusqlite::Error),
22
23 /// The CSV reader failed to parse the input (malformed record, unequal
24 /// field counts under `flexible = false`, encoding, …).
25 #[error("csv error: {0}")]
26 Csv(#[from] csv::Error),
27
28 /// A filesystem operation failed (creating the parent dir, opening the
29 /// CSV path, …).
30 #[error("io error: {0}")]
31 Io(#[from] std::io::Error),
32
33 /// A table identifier supplied to [`ingest_csv`](crate::DataStore::ingest_csv)
34 /// is not a safe SQLite identifier: empty, or containing a NUL byte or a
35 /// double-quote. Defense in depth on top of the always-on
36 /// double-quote quoting (Phase 21 — identifier safety is a review focus).
37 #[error("invalid SQL identifier `{0}`: table names may not be empty or contain NUL / double-quote characters")]
38 InvalidIdentifier(String),
39
40 /// A table referenced by [`summarize`](crate::DataStore::summarize) does
41 /// not exist in the database.
42 #[error("no such table: `{0}`")]
43 NoSuchTable(String),
44
45 /// The CSV had no header row, so no columns could be created.
46 #[error("empty csv: no header row")]
47 EmptyCsv,
48
49 /// An `.ipynb` notebook (Phase 21.4 — [`crate::notebook`]) could not be
50 /// read, parsed, or validated: the file is not valid JSON, its top-level
51 /// value is not an object, its `nbformat` is not `4`, or it is otherwise not
52 /// a well-formed nbformat-4 document. The message names the offending file
53 /// and the specific reason so the MCP adapter surfaces an honest, in-band
54 /// tool error the model can read (never a panic). See
55 /// [`docs/design/centaur-data-scientist.md`](../../../docs/design/centaur-data-scientist.md)
56 /// §4.1, the notebook-artifact bullet.
57 #[error("invalid notebook: {0}")]
58 InvalidNotebook(String),
59}
60
61/// Crate-wide result alias over [`DataError`].
62pub type Result<T> = std::result::Result<T, DataError>;