Skip to main content

aube_codes/
errors.rs

1//! Error codes (`ERR_AUBE_*`).
2//!
3//! Each constant's *value* matches its identifier. The `ALL` slice
4//! is the registry — it gates the generated docs page
5//! (`docs/error-codes.md`, produced by the
6//! `generate-error-codes-docs` binary) and the self-tests in
7//! `lib.rs`. New codes go in both places: define a `pub const`,
8//! then add a [`crate::CodeMeta`] entry to `ALL` carrying the
9//! category, one-line description, and (optional) bespoke exit
10//! code.
11
12use crate::CodeMeta;
13
14// ── lockfile ─────────────────────────────────────────────────────────
15pub const ERR_AUBE_NO_LOCKFILE: &str = "ERR_AUBE_NO_LOCKFILE";
16pub const ERR_AUBE_LOCKFILE_PARSE: &str = "ERR_AUBE_LOCKFILE_PARSE";
17pub const ERR_AUBE_LOCKFILE_UNSUPPORTED_FORMAT: &str = "ERR_AUBE_LOCKFILE_UNSUPPORTED_FORMAT";
18
19// ── resolver ─────────────────────────────────────────────────────────
20pub const ERR_AUBE_NO_MATCHING_VERSION: &str = "ERR_AUBE_NO_MATCHING_VERSION";
21pub const ERR_AUBE_NO_MATURE_MATCHING_VERSION: &str = "ERR_AUBE_NO_MATURE_MATCHING_VERSION";
22pub const ERR_AUBE_REGISTRY_ERROR: &str = "ERR_AUBE_REGISTRY_ERROR";
23pub const ERR_AUBE_UNKNOWN_CATALOG: &str = "ERR_AUBE_UNKNOWN_CATALOG";
24pub const ERR_AUBE_UNKNOWN_CATALOG_ENTRY: &str = "ERR_AUBE_UNKNOWN_CATALOG_ENTRY";
25pub const ERR_AUBE_BLOCKED_EXOTIC_SUBDEP: &str = "ERR_AUBE_BLOCKED_EXOTIC_SUBDEP";
26pub const ERR_AUBE_TRUST_DOWNGRADE: &str = "ERR_AUBE_TRUST_DOWNGRADE";
27pub const ERR_AUBE_TRUST_MISSING_TIME: &str = "ERR_AUBE_TRUST_MISSING_TIME";
28// `#[rustfmt::skip]` keeps the long names on a single visual line so the
29// declaration list reads as a flat table — rustfmt would otherwise wrap
30// to a `name: &str =\n    "name";` two-liner for any const past col 100.
31#[rustfmt::skip] pub const ERR_AUBE_TRUST_EXCLUDE_INVALID_VERSION_UNION: &str = "ERR_AUBE_TRUST_EXCLUDE_INVALID_VERSION_UNION";
32#[rustfmt::skip] pub const ERR_AUBE_TRUST_EXCLUDE_NAME_GLOB_WITH_VERSIONS: &str = "ERR_AUBE_TRUST_EXCLUDE_NAME_GLOB_WITH_VERSIONS";
33pub const ERR_AUBE_PEER_CONTEXT_NOT_CONVERGED: &str = "ERR_AUBE_PEER_CONTEXT_NOT_CONVERGED";
34
35// ── registry / network ──────────────────────────────────────────────
36pub const ERR_AUBE_PACKAGE_NOT_FOUND: &str = "ERR_AUBE_PACKAGE_NOT_FOUND";
37pub const ERR_AUBE_VERSION_NOT_FOUND: &str = "ERR_AUBE_VERSION_NOT_FOUND";
38pub const ERR_AUBE_UNAUTHORIZED: &str = "ERR_AUBE_UNAUTHORIZED";
39pub const ERR_AUBE_OFFLINE: &str = "ERR_AUBE_OFFLINE";
40pub const ERR_AUBE_INVALID_PACKAGE_NAME: &str = "ERR_AUBE_INVALID_PACKAGE_NAME";
41pub const ERR_AUBE_REGISTRY_WRITE_REJECTED: &str = "ERR_AUBE_REGISTRY_WRITE_REJECTED";
42
43// ── tarball / store ─────────────────────────────────────────────────
44pub const ERR_AUBE_TARBALL_INTEGRITY: &str = "ERR_AUBE_TARBALL_INTEGRITY";
45pub const ERR_AUBE_TARBALL_EXTRACT: &str = "ERR_AUBE_TARBALL_EXTRACT";
46pub const ERR_AUBE_PKG_CONTENT_MISMATCH: &str = "ERR_AUBE_PKG_CONTENT_MISMATCH";
47pub const ERR_AUBE_NO_HOME: &str = "ERR_AUBE_NO_HOME";
48pub const ERR_AUBE_GIT_ERROR: &str = "ERR_AUBE_GIT_ERROR";
49
50// ── linker ──────────────────────────────────────────────────────────
51pub const ERR_AUBE_LINK_FAILED: &str = "ERR_AUBE_LINK_FAILED";
52pub const ERR_AUBE_PATCH_FAILED: &str = "ERR_AUBE_PATCH_FAILED";
53pub const ERR_AUBE_MISSING_PACKAGE_INDEX: &str = "ERR_AUBE_MISSING_PACKAGE_INDEX";
54pub const ERR_AUBE_UNSAFE_INDEX_KEY: &str = "ERR_AUBE_UNSAFE_INDEX_KEY";
55pub const ERR_AUBE_MISSING_STORE_FILE: &str = "ERR_AUBE_MISSING_STORE_FILE";
56
57// ── scripts ─────────────────────────────────────────────────────────
58pub const ERR_AUBE_SCRIPT_SPAWN: &str = "ERR_AUBE_SCRIPT_SPAWN";
59pub const ERR_AUBE_SCRIPT_NON_ZERO_EXIT: &str = "ERR_AUBE_SCRIPT_NON_ZERO_EXIT";
60#[rustfmt::skip] pub const ERR_AUBE_BUILD_POLICY_UNSUPPORTED_VALUE: &str = "ERR_AUBE_BUILD_POLICY_UNSUPPORTED_VALUE";
61#[rustfmt::skip] pub const ERR_AUBE_BUILD_POLICY_INVALID_VERSION_UNION: &str = "ERR_AUBE_BUILD_POLICY_INVALID_VERSION_UNION";
62#[rustfmt::skip] pub const ERR_AUBE_BUILD_POLICY_WILDCARD_WITH_VERSION: &str = "ERR_AUBE_BUILD_POLICY_WILDCARD_WITH_VERSION";
63
64// ── workspace / filter ──────────────────────────────────────────────
65pub const ERR_AUBE_WORKSPACE_PARSE: &str = "ERR_AUBE_WORKSPACE_PARSE";
66pub const ERR_AUBE_FILTER_EMPTY: &str = "ERR_AUBE_FILTER_EMPTY";
67pub const ERR_AUBE_FILTER_GIT_IO: &str = "ERR_AUBE_FILTER_GIT_IO";
68pub const ERR_AUBE_FILTER_GIT_FAILED: &str = "ERR_AUBE_FILTER_GIT_FAILED";
69
70// ── manifest ────────────────────────────────────────────────────────
71pub const ERR_AUBE_MANIFEST_PARSE: &str = "ERR_AUBE_MANIFEST_PARSE";
72pub const ERR_AUBE_MANIFEST_YAML_PARSE: &str = "ERR_AUBE_MANIFEST_YAML_PARSE";
73
74// ── engine / cli ────────────────────────────────────────────────────
75pub const ERR_AUBE_UNSUPPORTED_ENGINE: &str = "ERR_AUBE_UNSUPPORTED_ENGINE";
76pub const ERR_AUBE_RECURSIVE_NOT_SUPPORTED: &str = "ERR_AUBE_RECURSIVE_NOT_SUPPORTED";
77pub const ERR_AUBE_UNKNOWN_COMMAND: &str = "ERR_AUBE_UNKNOWN_COMMAND";
78pub const ERR_AUBE_NPM_ONLY_COMMAND: &str = "ERR_AUBE_NPM_ONLY_COMMAND";
79pub const ERR_AUBE_COMPLETION_FAILED: &str = "ERR_AUBE_COMPLETION_FAILED";
80pub const ERR_AUBE_REMOVE_PRIOR_INSTALL_DIR: &str = "ERR_AUBE_REMOVE_PRIOR_INSTALL_DIR";
81pub const ERR_AUBE_CONFIG_NESTED_AUBE_KEY: &str = "ERR_AUBE_CONFIG_NESTED_AUBE_KEY";
82
83// ── misc tracing::error! sites (non-fatal but high-severity) ────────
84pub const ERR_AUBE_PATCHES_TRACKING_WRITE: &str = "ERR_AUBE_PATCHES_TRACKING_WRITE";
85pub const ERR_AUBE_UNSAFE_SHEBANG_INTERPRETER: &str = "ERR_AUBE_UNSAFE_SHEBANG_INTERPRETER";
86
87/// Stable category labels that group codes in the generated docs and
88/// in `EXIT_TABLE`'s 10-wide allocation ranges. Public so the docs
89/// generator can iterate them in a deterministic order.
90pub mod category {
91    pub const LOCKFILE: &str = "Lockfile";
92    pub const RESOLVER: &str = "Resolver";
93    pub const TARBALL_STORE: &str = "Tarball / store";
94    pub const REGISTRY_NETWORK: &str = "Registry / network";
95    pub const SCRIPTS: &str = "Scripts / build";
96    pub const LINKER: &str = "Linker";
97    pub const MANIFEST_WORKSPACE: &str = "Manifest / workspace";
98    pub const ENGINE_CLI: &str = "Engine / CLI";
99    pub const MISC_SAFETY: &str = "Misc / safety";
100}
101
102/// Registry of every error code with its category, description, and
103/// (optional) bespoke exit code. Walked by the
104/// `generate-error-codes-docs` binary and by the self-tests in
105/// `lib.rs` and `exit.rs`. New codes must be added here.
106pub const ALL: &[CodeMeta] = &[
107    // Lockfile
108    CodeMeta {
109        name: ERR_AUBE_NO_LOCKFILE,
110        category: category::LOCKFILE,
111        description: "An operation that required a lockfile (`--frozen-lockfile`, `aube fetch`, etc.) found none in the project.",
112        exit_code: Some(10),
113    },
114    CodeMeta {
115        name: ERR_AUBE_LOCKFILE_PARSE,
116        category: category::LOCKFILE,
117        description: "Lockfile is structurally invalid — version guard failed, YAML shape is wrong, or `yaml_serde` couldn't round-trip the contents.",
118        exit_code: Some(11),
119    },
120    CodeMeta {
121        name: ERR_AUBE_LOCKFILE_UNSUPPORTED_FORMAT,
122        category: category::LOCKFILE,
123        description: "Lockfile filename was recognized but its format isn't supported on this aube version.",
124        exit_code: Some(12),
125    },
126    // Resolver
127    CodeMeta {
128        name: ERR_AUBE_NO_MATCHING_VERSION,
129        category: category::RESOLVER,
130        description: "No published version of the named package satisfies the requested range.",
131        exit_code: Some(20),
132    },
133    CodeMeta {
134        name: ERR_AUBE_NO_MATURE_MATCHING_VERSION,
135        category: category::RESOLVER,
136        description: "A version satisfying the range exists but every candidate was younger than `minimumReleaseAge` and `minimumReleaseAgeStrict=true`.",
137        exit_code: Some(21),
138    },
139    CodeMeta {
140        name: ERR_AUBE_BLOCKED_EXOTIC_SUBDEP,
141        category: category::RESOLVER,
142        description: "Transitive dep used a `git:` / `file:` / `tarball` specifier and `blockExoticSubdeps=true`.",
143        exit_code: Some(22),
144    },
145    CodeMeta {
146        name: ERR_AUBE_TRUST_DOWNGRADE,
147        category: category::RESOLVER,
148        description: "Picked version dropped trust evidence the prior version had (`trustPolicy=no-downgrade`).",
149        exit_code: Some(23),
150    },
151    CodeMeta {
152        name: ERR_AUBE_TRUST_MISSING_TIME,
153        category: category::RESOLVER,
154        description: "Registry's packument has no `time` entry for the picked version (`trustPolicy=no-downgrade`).",
155        exit_code: Some(24),
156    },
157    CodeMeta {
158        name: ERR_AUBE_UNKNOWN_CATALOG,
159        category: category::RESOLVER,
160        description: "A `catalog:<name>` reference was used but the catalog isn't defined.",
161        exit_code: Some(25),
162    },
163    CodeMeta {
164        name: ERR_AUBE_UNKNOWN_CATALOG_ENTRY,
165        category: category::RESOLVER,
166        description: "The catalog exists but has no entry for the requested package.",
167        exit_code: Some(26),
168    },
169    CodeMeta {
170        name: ERR_AUBE_PEER_CONTEXT_NOT_CONVERGED,
171        category: category::RESOLVER,
172        description: "Peer-context fixed-point loop hit `MAX_ITERATIONS=16` without converging — usually mutually-recursive peers.",
173        exit_code: Some(27),
174    },
175    CodeMeta {
176        name: ERR_AUBE_REGISTRY_ERROR,
177        category: category::RESOLVER,
178        description: "Generic registry error from inside the resolver.",
179        exit_code: None,
180    },
181    CodeMeta {
182        name: ERR_AUBE_TRUST_EXCLUDE_INVALID_VERSION_UNION,
183        category: category::RESOLVER,
184        description: "A `trustPolicyExclude` pattern had a non-exact version.",
185        exit_code: None,
186    },
187    CodeMeta {
188        name: ERR_AUBE_TRUST_EXCLUDE_NAME_GLOB_WITH_VERSIONS,
189        category: category::RESOLVER,
190        description: "A `trustPolicyExclude` pattern combined a name glob with versions.",
191        exit_code: None,
192    },
193    // Tarball / store
194    CodeMeta {
195        name: ERR_AUBE_TARBALL_INTEGRITY,
196        category: category::TARBALL_STORE,
197        description: "Downloaded tarball's hash didn't match the lockfile's / packument's `dist.integrity`.",
198        exit_code: Some(30),
199    },
200    CodeMeta {
201        name: ERR_AUBE_TARBALL_EXTRACT,
202        category: category::TARBALL_STORE,
203        description: "Tarball couldn't be extracted (corrupt gzip, unexpected entry shape, etc.).",
204        exit_code: Some(31),
205    },
206    CodeMeta {
207        name: ERR_AUBE_PKG_CONTENT_MISMATCH,
208        category: category::TARBALL_STORE,
209        description: "Tarball's `package.json` declared a different `(name, version)` than the resolver expected (`strictStorePkgContentCheck=true`).",
210        exit_code: Some(32),
211    },
212    CodeMeta {
213        name: ERR_AUBE_GIT_ERROR,
214        category: category::TARBALL_STORE,
215        description: "Git operation failed during a `git:` dep prepare or checkout.",
216        exit_code: Some(33),
217    },
218    CodeMeta {
219        name: ERR_AUBE_NO_HOME,
220        category: category::TARBALL_STORE,
221        description: "`HOME` (or platform equivalent) is unset, so aube can't locate its store.",
222        exit_code: None,
223    },
224    // Registry / network
225    CodeMeta {
226        name: ERR_AUBE_PACKAGE_NOT_FOUND,
227        category: category::REGISTRY_NETWORK,
228        description: "Registry returned 404 for the package name.",
229        exit_code: Some(40),
230    },
231    CodeMeta {
232        name: ERR_AUBE_VERSION_NOT_FOUND,
233        category: category::REGISTRY_NETWORK,
234        description: "Package exists but the requested version doesn't.",
235        exit_code: Some(41),
236    },
237    CodeMeta {
238        name: ERR_AUBE_UNAUTHORIZED,
239        category: category::REGISTRY_NETWORK,
240        description: "Registry returned 401/403 — missing or invalid auth. Run `aube login`.",
241        exit_code: Some(42),
242    },
243    CodeMeta {
244        name: ERR_AUBE_OFFLINE,
245        category: category::REGISTRY_NETWORK,
246        description: "Offline mode and the requested resource isn't in the local cache.",
247        exit_code: Some(43),
248    },
249    CodeMeta {
250        name: ERR_AUBE_INVALID_PACKAGE_NAME,
251        category: category::REGISTRY_NETWORK,
252        description: "A name doesn't match npm's grammar — rejected before any I/O so a hostile manifest can't use the cache-path builder as a write primitive.",
253        exit_code: Some(44),
254    },
255    CodeMeta {
256        name: ERR_AUBE_REGISTRY_WRITE_REJECTED,
257        category: category::REGISTRY_NETWORK,
258        description: "Registry rejected a publish/deprecate/owner write with a non-2xx response.",
259        exit_code: Some(45),
260    },
261    // Scripts / build
262    CodeMeta {
263        name: ERR_AUBE_SCRIPT_NON_ZERO_EXIT,
264        category: category::SCRIPTS,
265        description: "A lifecycle script (`preinstall` / `install` / `postinstall` / a `package.json` script) exited non-zero.",
266        exit_code: Some(50),
267    },
268    CodeMeta {
269        name: ERR_AUBE_SCRIPT_SPAWN,
270        category: category::SCRIPTS,
271        description: "Couldn't spawn a script's interpreter (shell missing, jail setup failed, etc.).",
272        exit_code: Some(51),
273    },
274    CodeMeta {
275        name: ERR_AUBE_BUILD_POLICY_UNSUPPORTED_VALUE,
276        category: category::SCRIPTS,
277        description: "An entry in `allowBuilds` had a value that wasn't `true`/`false`.",
278        exit_code: None,
279    },
280    CodeMeta {
281        name: ERR_AUBE_BUILD_POLICY_INVALID_VERSION_UNION,
282        category: category::SCRIPTS,
283        description: "An `allowBuilds` pattern's version union was unparseable.",
284        exit_code: None,
285    },
286    CodeMeta {
287        name: ERR_AUBE_BUILD_POLICY_WILDCARD_WITH_VERSION,
288        category: category::SCRIPTS,
289        description: "An `allowBuilds` pattern combined a wildcard name with a version union.",
290        exit_code: None,
291    },
292    // Linker
293    CodeMeta {
294        name: ERR_AUBE_PATCH_FAILED,
295        category: category::LINKER,
296        description: "Applying a `pnpm.patchedDependencies` patch failed.",
297        exit_code: Some(60),
298    },
299    CodeMeta {
300        name: ERR_AUBE_LINK_FAILED,
301        category: category::LINKER,
302        description: "Symlink / junction / hardlink couldn't be created — usually permissions or filesystem support.",
303        exit_code: Some(61),
304    },
305    CodeMeta {
306        name: ERR_AUBE_MISSING_PACKAGE_INDEX,
307        category: category::LINKER,
308        description: "Internal: a caller skipped `load_index` but the package wasn't already materialized.",
309        exit_code: Some(62),
310    },
311    CodeMeta {
312        name: ERR_AUBE_MISSING_STORE_FILE,
313        category: category::LINKER,
314        description: "A package index references a CAS shard that doesn't exist on disk. Re-run install to re-fetch.",
315        exit_code: Some(63),
316    },
317    // Manifest / workspace
318    CodeMeta {
319        name: ERR_AUBE_MANIFEST_PARSE,
320        category: category::MANIFEST_WORKSPACE,
321        description: "A `package.json` had a syntax error. miette renders a pointer at the offending byte.",
322        exit_code: Some(70),
323    },
324    CodeMeta {
325        name: ERR_AUBE_WORKSPACE_PARSE,
326        category: category::MANIFEST_WORKSPACE,
327        description: "An `aube-workspace.yaml` / `pnpm-workspace.yaml` was structurally invalid.",
328        exit_code: Some(71),
329    },
330    CodeMeta {
331        name: ERR_AUBE_MANIFEST_YAML_PARSE,
332        category: category::MANIFEST_WORKSPACE,
333        description: "A workspace YAML helper file was structurally invalid (no source pointer available).",
334        exit_code: None,
335    },
336    CodeMeta {
337        name: ERR_AUBE_FILTER_EMPTY,
338        category: category::MANIFEST_WORKSPACE,
339        description: "`--filter` was passed an empty selector.",
340        exit_code: None,
341    },
342    CodeMeta {
343        name: ERR_AUBE_FILTER_GIT_IO,
344        category: category::MANIFEST_WORKSPACE,
345        description: "A `--filter ...[ref]` selector failed to spawn `git`.",
346        exit_code: None,
347    },
348    CodeMeta {
349        name: ERR_AUBE_FILTER_GIT_FAILED,
350        category: category::MANIFEST_WORKSPACE,
351        description: "The git subprocess for a `--filter ...[ref]` selector exited non-zero.",
352        exit_code: None,
353    },
354    // Engine / CLI
355    CodeMeta {
356        name: ERR_AUBE_UNSUPPORTED_ENGINE,
357        category: category::ENGINE_CLI,
358        description: "One or more packages declared an `engines` constraint incompatible with the running Node/aube and `engine-strict=true`.",
359        exit_code: Some(80),
360    },
361    CodeMeta {
362        name: ERR_AUBE_UNKNOWN_COMMAND,
363        category: category::ENGINE_CLI,
364        description: "The named subcommand isn't a built-in aube command and isn't a script in the manifest.",
365        exit_code: Some(81),
366    },
367    CodeMeta {
368        name: ERR_AUBE_NPM_ONLY_COMMAND,
369        category: category::ENGINE_CLI,
370        description: "The user invoked an npm-only command (`whoami`, `token`, `owner`, `search`, `pkg`, `set-script`) — aube doesn't implement these; use npm.",
371        exit_code: Some(82),
372    },
373    CodeMeta {
374        name: ERR_AUBE_RECURSIVE_NOT_SUPPORTED,
375        category: category::ENGINE_CLI,
376        description: "A command was invoked under `--recursive` but doesn't support recursive execution.",
377        exit_code: None,
378    },
379    CodeMeta {
380        name: ERR_AUBE_COMPLETION_FAILED,
381        category: category::ENGINE_CLI,
382        description: "`aube completion` couldn't invoke `usage` to render the shell completions.",
383        exit_code: None,
384    },
385    CodeMeta {
386        name: ERR_AUBE_REMOVE_PRIOR_INSTALL_DIR,
387        category: category::ENGINE_CLI,
388        description: "Couldn't clean up a prior global install dir before re-installing.",
389        exit_code: None,
390    },
391    CodeMeta {
392        name: ERR_AUBE_CONFIG_NESTED_AUBE_KEY,
393        category: category::ENGINE_CLI,
394        description: "`aube config set <prefix>.<sub> …` was used for a key whose prefix is an aube map setting (e.g. `allowBuilds.<pkg>`). Such nested writes would otherwise land in `.npmrc` where aube doesn't read them and npm warns/errors about the unknown key — set the map in workspace yaml or `package.json#aube.<prefix>` instead.",
395        exit_code: None,
396    },
397    // Misc / safety
398    CodeMeta {
399        name: ERR_AUBE_UNSAFE_INDEX_KEY,
400        category: category::MISC_SAFETY,
401        description: "A package index key tried to escape its directory (path traversal defense in depth).",
402        exit_code: Some(90),
403    },
404    CodeMeta {
405        name: ERR_AUBE_UNSAFE_SHEBANG_INTERPRETER,
406        category: category::MISC_SAFETY,
407        description: "A `#!` shebang named an unsafe interpreter when generating a shim — substituted with `node` instead. Surfaced as `tracing::error!` but install continues.",
408        exit_code: Some(91),
409    },
410    CodeMeta {
411        name: ERR_AUBE_PATCHES_TRACKING_WRITE,
412        category: category::MISC_SAFETY,
413        description: "Couldn't write `.aube-applied-patches.json` after applying patches. Non-fatal; next install may miss stale patched entries.",
414        exit_code: None,
415    },
416];