Errors

This page indexes every user-facing error message in Lattice, organized by the stage of a run that raises it: config loading, workspace discovery, task-graph construction, toolchain provisioning, cache operations, task execution, and version self-management. Paste a message you saw into your browser’s find (Ctrl/Cmd-F) to jump to it.

Most errors here are fatal: Lattice prints Error: <message> to stderr (an anyhow::Error’s chain adds a Caused by: section underneath when one error wraps another) and exits non-zero. A few are warnings — printed as lattice: warning: <message> and the run continues. Each entry below says which. For step-by-step fixes to the most common failures, see Troubleshooting; for the config fields mentioned throughout, see Configuration.

Config loading and validation

Raised while finding, reading, parsing, and validating lattice.json (crates/lattice-config/src/lib.rs, plus root-discovery calls in crates/lattice/src/commands/).

No lattice.json found

no lattice.json found in this directory or any parent; run `lattice init` to create one

Raised by lattice run, lattice setup, and lattice upgrade when root discovery walks up from the working directory and never finds a lattice.json. Fatal. Run lattice init, or cd into the repo.

lattice prune raises the same underlying condition but with a shorter message that drops the lattice init suggestion:

no lattice.json found in this directory or any parent

crates/lattice/src/commands/prune.rs:25, versus the fuller text at crates/lattice/src/commands/run.rs:65-70, setup.rs:35-40, and upgrade.rs:30-35. Worth normalizing in the code so every command suggests lattice init the same way.

Config file unreadable or unparseable

failed to read lattice.json from /repo
failed to parse lattice.json

The first wraps a filesystem error (permissions, a directory named lattice.json, and so on); the second wraps the underlying serde_json error (with the line/column) when the file exists but is not valid JSON, or fails to match the shape of LatticeConfig. Both fatal, both from load_config (crates/lattice-config/src/lib.rs:328-336).

Engine declared in unsupported string form

engine 'alpes' in root uses the string (version-only) form, but 'alpes' is not
a well-known engine Lattice can version-check on its own. Use the object form
with an explicit `versionCmd`, e.g. "alpes": { "version": ">=1.0.0", "versionCmd":
"alpes --version" }

Raised by LatticeConfig::validate when an engines entry (root or per-workspace) is a bare version string but its name is not in WELL_KNOWN_ENGINES (crates/lattice-config/src/lib.rs:304-316; the full list is on Toolchains). Fatal. Fix by switching to the object form with an explicit versionCmd, exactly as the message shows.

Workspace has an empty path

workspace 'web' has an empty path

The path field of a workspace is present but blank or whitespace-only. Fatal. crates/lattice-config/src/lib.rs:289.

Duplicate workspace name (config-level)

duplicate workspace name 'web': workspace names must be unique

Two entries in the workspaces array share a name. Fatal. crates/lattice-config/src/lib.rs:292-296. (A second, textually different check for the same condition exists at the discovery stage — see Duplicate workspace name (discovery) below.)

Invalid or missing cache size

Raised by CacheSize::parse (crates/lattice-config/src/lib.rs:143-176), used for both settings.maxCacheSize in lattice.json and lattice prune --max-size:

cache size is empty
cache size '10XB' has no numeric component
invalid numeric component in cache size '10..5GB'
unknown cache size unit 'XB' in '10XB'

All fatal. Valid units are B, KB, MB, GB, TB (case-insensitive, base 1024) or a bare integer of bytes, e.g. "10GB" or "1048576".

lattice prune also fails when no limit is available at all:

no max cache size set (pass --max-size or set settings.maxCacheSize in lattice.json)

Fatal. crates/lattice/src/commands/prune.rs:34-37. Pass --max-size, or set settings.maxCacheSize in lattice.json.

Workspace discovery and driver detection

Raised while turning the workspaces array into resolved Workspace values — checking paths, and picking each workspace’s task driver via the evidence ladder (crates/lattice-workspace/src/lib.rs). See Driver detection for the model.

Ambiguous or undeclared task driver

The evidence ladder’s halt condition, AmbiguityError (crates/lattice-workspace/src/lib.rs:355-386). Fatal, and it is the only error whose text is built dynamically from what Lattice actually found in the workspace directory. Three shapes:

No evidence at all (e.g. only a .nvmrc, a runtime with no package manager or task runner on top of it):

workspace 'app' has an ambiguous or undeclared task driver.
No task driver could be detected (no lockfile, wrapper, or native declaration).
Declare the task driver explicitly by adding to this workspace in lattice.json:
  "engines": { "node": ">=0.0.0" }

A bare generic ecosystem marker (e.g. only package.json, no lockfile):

workspace 'app' has an ambiguous or undeclared task driver.
Candidate tools seen: pnpm, npm, yarn, bun
Declare the task driver explicitly by adding to this workspace in lattice.json:
  "engines": { "pnpm": ">=0.0.0" }

Two same-role tools present at once (e.g. both bun.lockb and pnpm-lock.yaml):

workspace 'web' has an ambiguous or undeclared task driver.
Candidate tools seen: bun, pnpm
Declare the task driver explicitly by adding to this workspace in lattice.json:
  "engines": { "bun": ">=0.0.0" }

In every case, fix it by pasting the suggested engines line into that workspace’s config (or naming whichever tool you actually use). This halt only fires for a workspace whose auto is true (the default) — set auto: false to declare scripts yourself instead.

Workspace path is not a directory

workspace path 'apps/gone' does not point to a directory; workspace paths are
literal directories, not globs

Raised by discover_workspaces when a configured path doesn’t resolve to an existing directory (crates/lattice-workspace/src/lib.rs:736-742). Fatal. A common cause is treating path as a glob — it never is; see Workspaces.

Duplicate workspace name or path (discovery)

duplicate workspace name 'web' in lattice.json
duplicate workspace path 'apps/web' in lattice.json

Raised during discovery (crates/lattice-workspace/src/lib.rs:745-751), after the config-level uniqueness check already described above. The second form fires even when two workspace entries have different names but the same resolved directory (after canonicalization). Both fatal.

Task graph construction

Raised while expanding the root tasks map across resolved workspaces into the execution DAG (crates/dagger/src/lib.rs). See Task graph.

Unknown task

lattice run checks every requested task name against lattice.json before building any graph:

task 'lint' is not defined in lattice.json; available tasks: build, test

(or available tasks: (none defined) when tasks is empty). Fatal. crates/lattice/src/commands/run.rs:76-89. dagger itself carries an equivalent, textually different defensive check for library callers that skip that pre-check:

task 'lint' is not defined in the tasks section of lattice.json

crates/dagger/src/lib.rs:100-105. Through the CLI you will always see the first form first.

Manual workspace declares no command for a requested task

workspace 'legacy' is "auto": false but declares no command for task 'build';
add it under this workspace's "scripts" map in lattice.json

A workspace with auto: false opts out of all inference — it never invents a command for a task, so a requested root task with nothing in that workspace’s scripts map halts the whole run. (An auto: true workspace instead skips the task quietly if its driver doesn’t apply.) Fatal. crates/dagger/src/lib.rs:135-142.

Persistent task depended on

persistent task 'dev' in workspace 'web' cannot be depended on by other tasks

A persistent: true task never completes, so nothing may declare it as a dependsOn. Fatal. crates/dagger/src/lib.rs:193-207. See Persistent tasks.

Cycle in the task graph

cycle detected in task dependency graph

dependsOn edges (same-workspace or ^-prefixed cross-workspace) form a cycle, so no topological order exists. Fatal. crates/dagger/src/lib.rs:210-212.

Toolchain resolution and provisioning

Raised while classifying and satisfying each engines constraint — host, validate, or provision (crates/lattice-workspace/src/toolchain.rs). See Engines and provisioning.

Validate-only failures

For an engine with a version constraint but no installCmd:

engine 'alpes': version command `alpes --version` failed:
alpes: command not found

The version command exited non-zero (commonly: the tool isn’t installed).

engine 'alpes': could not parse version from `alpes --version` output: unknown

The version command succeeded but its output had no recognizable number in it (parse_version looks for the first run of digits and dots).

engine 'alpes' has a version constraint but no way to check it (not a
well-known engine and no `versionCmd`)

An object-form engine gave a version constraint but no versionCmd, and the name isn’t well-known enough to have a built-in one. Add versionCmd.

engine 'alpes' 1.4.0 on PATH does not satisfy constraint '>=2.0.0'

The tool is present and its version parsed, but doesn’t satisfy the constraint. Install/upgrade the tool on PATH, or loosen the constraint.

All four fatal. crates/lattice-workspace/src/toolchain.rs:260-289.

Provisioning failures

For an engine with an installCmd:

failed to create toolchain dir /repo/.lattice/toolchains/alpes

Wraps a filesystem error creating the content-addressed install directory.

engine 'alpes': installCmd failed:
curl: (6) Could not resolve host: alpes.example

The installCmd itself exited non-zero; the combined stdout+stderr is appended verbatim.

failed to move toolchain into place: /repo/.lattice/toolchains/alpes/tmp-a1b2c3d4 -> /repo/.lattice/toolchains/alpes/1.4.0-a1b2c3d4

The install succeeded but renaming the staged directory into its final, version-stamped path failed (rare; typically a filesystem/permissions issue).

engine 'alpes': version command `alpes --version` failed after install:
alpes: command not found

The install command exited 0, but the version command against the freshly installed bin dir still failed — often a wrong bin path in the engine spec.

engine 'alpes' provisioned 1.4.0 does not satisfy '>=2.0.0'

The freshly installed tool’s own version doesn’t satisfy the declared constraint — the installCmd installed the wrong version.

All five fatal. crates/lattice-workspace/src/toolchain.rs:296-389. A rarer, underlying failure from either mode:

failed to spawn `alpes --version`

Wraps an OS error spawning the shell that runs the version/install command (in practice, sh itself missing). crates/lattice-workspace/src/toolchain.rs:145-147.

Cache operations

Raised by cache identity (hashing) and storage (crates/lattice-cache/src/lib.rs). See Caching for the model and Cache internals for the on-disk format.

The load-bearing rule: a lookup is a hit only if the metadata parses, the tarball opens, and its sha256 matches the recorded digest. A missing file, an unparseable meta, or a corrupted tarball is a miss — never an error, never a false hit — and the task simply re-runs. Nothing in this section fires on that path.

Cache-key computation failure (fatal — fails the task)

failed to compute cache key: failed to read input file src/main.rs

Raised inline in the runner before a task starts, if hashing the task’s inputs globs fails (usually a file that disappeared mid-glob) — wraps compute_key’s own errors:

failed to read input file <path>
failed to read lockfile <path>

Both from crates/lattice-cache/src/lib.rs:389-403. This is the one cache error that fails the task outright (crates/lattice-runner/src/lib.rs:518-536); every other cache failure below is a non-fatal warning.

Read/write warnings (non-fatal)

Printed as lattice: warning: <message> by the reporter and otherwise ignored:

app:build: cache lookup failed: failed to parse cache metadata at /repo/.lattice/cache/<key>.meta.json
app:build: failed to restore cached outputs: failed to unpack artifact into /repo/apps/app
app:build: failed to cache outputs: failed to create cache dir /repo/.lattice/cache

These wrap LocalStore’s own errors — failed to parse cache metadata at <path>, failed to read <path>, failed to write cache metadata at <path>, failed to create cache dir <path>, failed to create artifact <path>, failed to add <path> to artifact, failed to digest artifact <path>, failed to open artifact <path>, failed to unpack artifact into <path> (crates/lattice-cache/src/lib.rs:112-228). A lookup failure or a restore failure both fall through to running the task fresh; a store failure just warns after a successful run. None of these fail the build.

prune cache-directory read failure (fatal)

failed to read cache dir /repo/.lattice/cache

LocalStore::prune treats a missing cache directory as nothing to prune, but any other read error (permissions) is fatal. crates/lattice-cache/src/lib.rs:259-264.

Task execution

Raised by the scheduler while actually running task commands (crates/lattice-runner/src/lib.rs).

A task failed (fail-fast — the default)

task 'app:build' failed, stopping pipeline

The first task failure in a run without --continue stops scheduling new work; already-running tasks finish, then this is the process’s fatal error and the exit code is non-zero. crates/lattice-runner/src/lib.rs:417-431. The task’s own captured stdout/stderr is surfaced above this line.

One or more tasks failed (--continue / keep-going)

2 tasks failed (kept going); 3 downstream tasks skipped

With --continue, independent branches keep running after a failure; anything downstream of the failure is skipped rather than started. This summary is the final error (RunFailure, crates/lattice-runner/src/lib.rs:44-70), and the run still exits non-zero.

Task command failed to spawn

failed to spawn task shell (is `sh` available?): No such file or directory (os error 2)

The platform shell (sh on unix, cmd on Windows) could not be spawned at all — distinct from the task’s own command failing, which is a normal non-zero exit and not this message. crates/lattice-runner/src/lib.rs:597-613. Any other spawn error (not “not found”) uses a shorter form:

failed to spawn task: <os error>

Runner panic (fatal even with --continue)

task runner panicked: <panic message>

A spawned task’s async work panicked — a Lattice-internal fault, not a task failure. Treated as fatal regardless of --continue, since the scheduler’s own state can no longer be trusted. crates/lattice-runner/src/lib.rs:388-397. If you see this, it’s worth filing: it means a bug in Lattice, not your task.

lattice setup failures

web: `pnpm install` failed

A workspace’s dependency-install command exited non-zero; printed as a warning per workspace, and setup continues to the remaining workspaces. crates/lattice/src/commands/setup.rs:144-151. After all workspaces are attempted, if any failed:

one or more workspaces failed setup

Fatal — this is what makes lattice setup’s exit code non-zero. crates/lattice/src/commands/setup.rs:154-156.

Two related conditions from lattice run are not errors — they print a message and exit 0: a --filter that matches no workspace (lattice: no workspaces matched filter '<pattern>'.), and a repo with an empty workspaces array (lattice: no workspaces declared. Add them to the workspacesarray in lattice.json to run.). Both in crates/lattice/src/commands/run.rs:105-125.

Version pinning and self-update

Raised by lattice upgrade and by the automatic version-pin handover that runs before most commands (crates/lattice/src/release.rs, crates/lattice/src/drift.rs, crates/lattice/src/commands/upgrade.rs). See Upgrading for the normal-path behavior of latticeVersion pinning and the drift nag.

Not a version

'v1.x' is not a version (expected something like 0.2.0)

lattice upgrade <version> (or the pinned latticeVersion a repo asks to switch to) didn’t parse as semver. Fatal. crates/lattice/src/release.rs:53-59.

No fetcher available

neither `curl` nor `wget` is on PATH; install one, or download the release
archive by hand into .lattice/bin

Fetching a release (for lattice upgrade, or the automatic handover to a pinned version) needs one of these two tools; neither was found. Fatal. crates/lattice/src/release.rs:367-368.

Download or fetch failure

failed to download https://github.com/latticeandcompany/lattice/releases/download/v0.4.0/lattice-0.4.0-aarch64-apple-darwin.tar.gz: curl: (6) Could not resolve host
failed to fetch https://api.github.com/repos/latticeandcompany/lattice/releases?per_page=20: curl: (6) Could not resolve host

Both wrap the fetcher’s own stderr. Fatal. crates/lattice/src/release.rs:370-416.

Checksum mismatch

checksum mismatch for lattice-0.4.0-aarch64-apple-darwin.tar.gz
  expected 9f2c...
  actual   1a0b...
refusing to install a binary that does not match the published release

The downloaded archive’s sha256 doesn’t match the release’s checksums file. Fatal, and deliberate — Lattice refuses to install it. crates/lattice/src/release.rs:177-183. A related, rarer failure when the checksums file itself doesn’t cover this platform:

lattice-0.4.0-checksums.txt does not list lattice-0.4.0-aarch64-apple-darwin.tar.gz; this platform may not be published for 0.4.0

crates/lattice/src/release.rs:171-176.

No release to install

no release to install; tried https://api.github.com/repos/latticeandcompany/lattice/releases/latest and https://api.github.com/repos/latticeandcompany/lattice/releases?per_page=20

lattice upgrade latest found nothing published at either endpoint. Fatal. crates/lattice/src/release.rs:264-268.

Archive has no binary

/repo/.lattice/bin/.staging-0.4.0-12345/lattice-0.4.0-aarch64-apple-darwin.tar.gz contains no lattice

The downloaded archive was read but had no lattice entry inside. Fatal. crates/lattice/src/release.rs:354.

A version isn’t installed when linking

/repo/.lattice/bin/lattice-0.4.0 is not installed

link_stable was asked to point the stable lattice symlink at a version-stamped binary that isn’t on disk. Fatal. crates/lattice/src/release.rs:208. In normal use ensure_installed always runs first, so this indicates an internal ordering bug if you see it.

Automatic handover failed

this repo pins lattice 0.4.0, which is not installed and could not be fetched.
Run with --no-version-check to use lattice 0.3.1 anyway

Any command run in a repo whose latticeVersion differs from the invoked binary tries to install and switch to the pinned version first (crates/lattice/src/drift.rs:99-136); this wraps whatever ensure_installed/release error occurred (see the checksum, fetch, and fetcher errors above) with the escape hatch spelled out. Fatal unless you pass --no-version-check or set LATTICE_NO_VERSION_CHECK (see Environment variables), in which case the handover is skipped entirely and no error occurs.

lattice.json unreadable/unwritable during upgrade

failed to read /repo/lattice.json
failed to write /repo/lattice.json

lattice upgrade reads the file to find the current pin and text-edits it in place to avoid reformatting the rest of the file; either step can fail on a filesystem error. Fatal. crates/lattice/src/commands/upgrade.rs:38-39,72-74.