Exit codes and errors
Exit codes
| CODE | MEANING | APPLIES TO |
|---|---|---|
| 0 | The command did what it was asked. | All |
| 1 | A blocking rule was violated, or the command could not complete a job it had started — a malformed bundle, an unresolved cluster reference, name drift. | All |
| 2 | A precondition failed, so nothing was checked: no credential, an unknown target, missing workload words, pricing unavailable, an interactive command with no terminal. | All |
1 and 2 both fail the step, and they deserve different responses. 1 from guard is the product working. 2 means nothing was checked, so treating it as a pass leaves the pipeline ungated.Target errors
Target Error: databricks.yml: target 'prd' is not declared by this bundle.
Declared targets: dev, staging, prod.A typo, or a target that exists in a different bundle. Use one of the names the error lists. The check happens before the platform is contacted, so it costs no round trip.
Target Error: databricks.yml: this bundle declares no targets, so there is no
environment to cost. Add a `targets:` block to the bundle.A bundle with no targets: block cannot be priced for an environment, because it does not describe one.
Workload gate errors
Workload Error: Missing workload entries for 2 compute(s) in finowl.yml:
- job:daily_ingest → serverless
- pipeline:customer_scd
Accepted words: trivial, light, medium, heavy, intensive.
Run `finowl init` to detect computes and scaffold the entries.Every gap at once, before any pricing call, so the complete to-do list is available with no credentials and no network. Run finowl init --target <t> for the target named in the command.
Workload Error: finowl.yml: 'estimations.defaults' is no longer supported —
workload words are per target now, so one environment cannot price another.
Run `finowl init --target <target>` once for each target your bundle declares,
then delete the 'defaults' block.A file written by version 0.1. It is refused rather than migrated: nothing can know whether prod deserved dev's numbers. See finowl.yml reference.
Workload Error: finowl.yml: file not found.The bundle was never registered, or finowl.yml was not committed. In CI the second is the common one — the file is read, never written, by a pipeline.
Identity errors
Missing identity block
finowl.yml: 'estimation.id' is required — it is the identity this project
reports under. Run `finowl init` to register, or copy the block from the
project's page on the platform.Unknown project
Unknown project: finowl.yml declares 6f1c9a2e-..., which does not exist in
your workspace.
Copy the identity block from the project's page, or run `finowl init` to
register a new one.Either the project was deleted, or the credential belongs to a different organization. finowl auth describe tells you which organization you are acting as.
Wrong organization
╭─ Wrong organization ─────────────────────────────────────────────╮
│ finowl.yml belongs to organization Acme EU, but you are │
│ authenticated to Acme Data Platform. │
│ Switch profile (--profile), or remove the copied identity block │
│ and run `finowl init` to register this bundle. │
╰──────────────────────────────────────────────────────────────────╯Usually a copied finowl.yml, occasionally the wrong profile. The first is worth checking for even when switching profiles fixes the symptom — two bundles pointing at one project mix their costs silently.
Name drift
╭─ Name drift ─────────────────────────────────────────────────────╮
│ finowl.yml says finance-reporting, but this project is │
│ registered as reporting-q3. │
│ Run `finowl rename finance-reporting` to make it official, │
│ or revert the file. │
╰──────────────────────────────────────────────────────────────────╯A warning in breakdown, a failure in guard. Fix it with finowl rename, which changes both sides together.
Authentication errors
Authentication Error: profile 'acme-eu' is not configured (available: DEFAULT).
Run `finowl auth login --profile acme-eu`.A named profile with no stored login is an error, not a fallback. Quietly authenticating as somebody else is how a run ends up filed against the wrong organization.
finowl auth login is interactive-only and cannot run without a terminal.
CI authenticates without secrets — see `finowl auth login --help`.A pipeline that reaches this has a configuration problem. See Run it in CI.
- In GitHub Actions, the usual cause is a missing
permissions: id-token: writeon the job. The permission is per job, not per workflow. - In any CI system,
finowl auth describereports which step of the chain won and which identity it resolved.
Bundle errors
Bundle file not found: databricks.yml
Hint: use --bundle to specify a path, e.g. finowl breakdown --bundle path/to/databricks.yml╭─ Bundle Validation — 1 cluster assignment warning ────────────────╮
│ ✗ job_cluster_key shared_main is not defined │
│ Job: daily_ingest │
│ At: resources.jobs.daily_ingest.tasks[0] │
╰───────────────────────────────────────────────────────────────────╯
Fix the undefined job_cluster_key references before running breakdown.A task referencing a cluster the job does not declare. This fails rather than warns because a cluster that is not there makes the cost wrong rather than missing — the task would be priced as if it had no compute.
Databricks CLI not founddiff and guard run databricks bundle plan, and breakdown runs databricks bundle validate. Install the Databricks CLI and configure workspace credentials the way you already do for bundle deploy.
Pricing errors
Pricing Error: could not fetch pricing dataRates are fetched live from the platform rather than shipped in the package, so a breakdown reflects current list prices. An unreachable platform stops the command with exit 2 rather than pricing from something stale.
Diagnosing anything else
finowl auth describe— which credential, which organization, which host.finowl COMMAND --help— the authoritative option reference for the version installed.finowl --version— worth checking first when CI behaves differently from your laptop, especially if the pipeline install is unpinned.-o json— the machine-readable envelope carries the same error string undererror, which is easier to capture from a pipeline log.