---
title: "Metadata and Exit Codes"
description: "Metadata and Exit Codes"
type: "docs"
category: "doc"
tags: []
authors: [Anonymous]
date: "2026-10-10"
last_update: "2026-10-10"
time_minutes: 3
draft: false
unlisted: false
url: "https://www.derafu.dev/docs/core/backbone-console/exit-codes"
---

# Metadata and Exit Codes

## Execution Metadata: `-v`

The response payload's *shape* never depends on where it is written, only on `-v`/`--verbose` — and only for how *much* ends up in it, never whether `meta`/`data_type`/`timestamp` are there at all (they always are). Without `-v`, `meta` has just `timestamp`/`data_type`, as shown above. With it, the rest of [`ExecutionMetadata`](https://www.derafu.dev/docs/core/backbone-dispatcher/results#execution-metadata-executionmetadata) (`startedAt`, timing, memory, CPU, load average) is merged into that same `meta` on success, or into `extensions` on failure (next to the already-present `debug`/`context`/`throwable`) — never a new top-level key:

```bash
bin/console -v billing:invoice:builder:build request.json
```

```json
{
    "meta": {
        "timestamp": 1755500000.123456,
        "data_type": "App\\Entity\\Invoice",
        "startedAt": "2026-01-20T10:00:00+00:00",
        "finishedAt": "2026-01-20T10:00:00+00:00",
        "realTime": 0.0234,
        "userTime": 0.0198,
        "systemTime": 0.0012,
        "memoryUsed": 131072,
        "peakMemory": 4194304,
        "pid": 12345,
        "loadAverage1Min": 0.52,
        "loadAverage5Min": 0.61,
        "loadAverage15Min": 0.58
    },
    "data": { "id": "INV-001" }
}
```

## Exit Codes

`bin/console help <command>` always lists every exit code that specific command can return — the fixed ones below, plus whatever the injected `ExitCodeResolverInterface` reports via `describe()` (see next section).

| Code | Meaning |
| --- | --- |
| `0` | Success. |
| `1` | The operation failed, and nothing more specific applies (`DefaultExitCodeResolver`'s fallback). |
| `10`–`16` | One of `derafu/backbone-dispatcher`'s own 7 generic exceptions — see below. |
| `65` (`EX_DATAERR`) | The request could not be parsed as JSON/YAML/XML. |
| `66` (`EX_NOINPUT`) | The input file does not exist or is not readable. |
| `70` (`EX_SOFTWARE`) | An unexpected internal error — a bug, not a usage or business problem. |
| `73` (`EX_CANTCREAT`) | `--output`/`--error-output` could not be created. |

`65`/`66`/`70`/`73` are [`sysexits(3)`](https://man.freebsd.org/cgi/man.cgi?query=sysexits) codes — a real BSD convention (`/usr/include/sysexits.h` on macOS/BSD), chosen because they start at `64` specifically to avoid colliding with whatever small integers other programs already use for their own exit codes. `2` (Symfony Console's own `Command::INVALID`) is reserved but currently unused by this package.

### `ExitCodeResolverInterface`: Mapping Exceptions to Codes

Every failure not caused by this command itself (a `ProblemDetailInterface`, produced by the dispatch) goes through `ExitCodeResolverInterface::resolve()`. `DefaultExitCodeResolver` — the default — already maps the 7 exceptions generic to *any* Backbone-based project, since they mean the same thing regardless of domain:

| Code | Exception |
| --- | --- |
| `10` | `OperationNotFoundException` |
| `11` | `OperationNotAllowedException` |
| `12` | `MissingParameterException` |
| `13` | `InvalidParameterTypeException` |
| `14` | `ClassNotFoundException` |
| `15` | `FromArrayMethodNotFoundException` |
| `16` | `NoDeserializerFoundException` |

A project that also wants its *own* business exceptions mapped extends `DefaultExitCodeResolver` rather than starting from nothing, layering its mapping on top via `parent::`:

```php
use Derafu\BackboneConsole\Service\DefaultExitCodeResolver;
use Derafu\BackboneDispatcher\Contract\ProblemDetailInterface;

class MyExitCodeResolver extends DefaultExitCodeResolver
{
    public function resolve(ProblemDetailInterface $problem): int
    {
        return match ($problem->getThrowable()->getClass()) {
            MyBusinessException::class => 20,
            default => parent::resolve($problem),
        };
    }

    public function describe(): array
    {
        return [MyBusinessException::class => 20] + parent::describe();
    }
}
```

Codes `>= 10` are the convention for a project's own mapping — clear of Symfony Console's `0`/`1`/`2`, `DefaultExitCodeResolver`'s own `10`–`16`, and the `64`–`78` `sysexits(3)` range this package uses internally.



---
Last updated on 10/10/2026

