# Diagnostics (DIAG_* reference)

Every DIAG_* code AfterPack emits, what triggered it, how to resolve it, and the exit codes a build returns.

Source: https://www.afterpack.dev/docs/diagnostics

AfterPack never ships weaker protection than you asked for. When something can't be resolved automatically, the build stops with a named `DIAG_*` code and a specific fix.

## Severity levels

Every diagnostic AfterPack emits is exactly one of three severities. There is no `Warning` severity.

| Severity | Meaning | What happens |
|---|---|---|
| **Info** | Expected behavior: you already acknowledged this, or the engine took a safe, correctness-preserving fallback. | Build succeeds, output written. |
| **Error** | Your stated requirements can't be met without a change on your end (a size cap that's too tight, a parse error, an invalid key). | Non-zero exit, **no output written**. |
| **Critical** | An engine bug. No action on your end fixes this. | Non-zero exit, no output written, always. [File a report.](mailto:security@afterpack.dev) |

## Exit codes

`npx afterpack@latest` returns one of seven codes. Script against them directly.

| Code | Meaning |
|---|---|
| `0` | Success. Every collected file was obfuscated and written. `--help` and `--version` also exit `0`. |
| `1` | Failure. No usable output was produced, and a message on stderr names what happened. |
| `2` | Partial. Some files shipped unobfuscated — only reachable with [`allowUnobfuscated`](https://www.afterpack.dev/docs/config#allowUnobfuscated). |
| `3` | Size cap. [`inflation.max`](https://www.afterpack.dev/docs/config#inflation-max) could not reach the complexity target (`DIAG_SIZE_CAP_REACHED`). |
| `4` | **Reserved.** A Pro feature requested without a key, or a lapsed entitlement. Documented, never emitted. |
| `5` | **Reserved.** Runtime reflection detected without [`reflection.allow`](https://www.afterpack.dev/docs/config#reflection-allow). Documented, never emitted. |
| `64` | Misuse. An unknown flag or command, a malformed value, or a duplicated path argument. |

### What makes a build exit 64

Usage problems stop the run before it starts.

- An unknown flag, an unknown command, a malformed value, or more than one positional path. The usage line reprints with the error.

### What makes a build exit 1

- No `<path>` argument and no build output found (`dist/`, `build/`, `out/`, `.output/`, `.next/`, or the conventional directory of the bundler named in `package.json`). AfterPack never reads a bundler's own config file, so a custom output directory is not detected this way.
- The build directory does not exist, or contains no `.js`/`.mjs`/`.cjs` files. An empty build directory fails the build. The usual cause is pointing at the wrong directory or running before the build.
- A file failed outright, or came back with empty output where the input was non-empty.
- A file the engine cannot obfuscate safely. The build fails and names the affected files. Use [`paths.exclude`](https://www.afterpack.dev/docs/config#paths-exclude) to carve out a file that must ship untouched.
- A failed `verify` or a failed `audit` scan.
- Any code below carrying `Error` or `Critical` severity.

### Fail closed, no exceptions

A Pro build either ships Pro-level protection or it doesn't ship.

*(fail-closed request-flow diagram — see the web page)*

Once a [`key`](https://www.afterpack.dev/docs/config#key) resolves, from [`AFTERPACK_key`](https://www.afterpack.dev/docs/config#key) or `afterpack.json`, the build is a cloud build. If the cloud call fails for any reason, the engine returns an error and the build exits `1`. It does not fall back to the local Free engine, and it does not emit unobfuscated output. There is no flag that ships unobfuscated output. Stopping the build puts the problem where you can see it.

This contract does not change with the invocation path: `npx afterpack@latest` and a plugin's auto-run on bundle close behave identically.

### Exit codes in CI

```bash
npx afterpack@latest dist/ || {
  echo "AfterPack failed: nothing shipped. See the error above."
  exit 1
}
```

Non-zero stops the pipeline. The reason appears on stderr and in the codes below.

## Complete reference

### Engine

| Code | Meaning |
|---|---|
| `DIAG_TARGET_REACHED` | Info. The engine reached the requested [`complexity`](https://www.afterpack.dev/docs/config#complexity). |
| `DIAG_TARGET_NOT_REACHED` | Info. The depth cap stopped inflation before the target; output is valid, just shallower. |
| `DIAG_INFLATION_BUDGET_HIT` | Info. A size-adding stage stopped at the resolved [inflation budget](https://www.afterpack.dev/docs/config#inflation-max) before reaching the target. Output is valid and floor-preserving. |
| `DIAG_SIZE_CAP_REACHED` | An explicit [`inflation.max`](https://www.afterpack.dev/docs/config#inflation-max) blocked reaching the target. Raise it, lower [`complexity`](https://www.afterpack.dev/docs/config#complexity), or exclude the file with [`paths.exclude`](https://www.afterpack.dev/docs/config#paths-exclude). |
| `DIAG_PATH_EXCLUDED` | Info. A file matched [`paths.exclude`](https://www.afterpack.dev/docs/config#paths-exclude) and shipped byte for byte; its bytes are counted as user-excluded. |
| `DIAG_SURVIVING_READABLE_LITERAL` | More readable string literals remain than [`strings.leaks.max`](https://www.afterpack.dev/docs/config#strings-leaks-max) allows. Raise [`complexity`](https://www.afterpack.dev/docs/config#complexity), lower [`strings.minLength`](https://www.afterpack.dev/docs/config#strings-minLength), or raise the limit. |
| `DIAG_SOURCE_MAP_INTEGRITY` | Error. A supplied upstream `.map` failed validation against its input. No output is written. |
| `DIAG_OUTPUT_UNPARSEABLE` | Error, and a signal of an engine bug. Re-parsing the output failed, so no output is written. |
| `DIAG_PARSE_ERROR` | Error. An input chunk didn't parse. AfterPack runs strictly post-build, on emitted JavaScript: compile first, then point it at the JS output. |
| `DIAG_CONFIG_PARSE_ERROR` | Error. The [engine config](https://www.afterpack.dev/docs/config) JSON didn't deserialize. |
| `DIAG_INPUT_TOO_LARGE` | A single input exceeded the size ceiling. |
| `DIAG_BATCH_TOO_LARGE` | A batch past 500 MB total (413, non-retryable); the build fails closed. |
| `DIAG_ENGINE_BUG_NO_PROGRESS` | Critical. The engine made no progress. This is an engine bug. |
| `DIAG_ENGINE_BUG_NO_APPLICABLE_TRANSFORM` | Critical. No applicable transform was available. This is an engine bug. |
| `DIAG_ENGINE_BUG_PROCESS_THREAD_PANIC` | Critical. A worker thread panicked. This is an engine bug. |

### Build plugin / CLI

| Code | Meaning |
|---|---|
| `DIAG_DIRECTIVE_UNKNOWN` | An `@afterpack` directive named an unrecognised key. Check it against [which keys](https://www.afterpack.dev/docs/directives#what-you-can-set) a region can override. |
| `DIAG_DIRECTIVE_UNSUPPORTED_FORM` | The marker form can't be placed (`// @afterpack …` line comment, or `@afterpack:begin/:end` span). Use `/* @afterpack … */` block markers. |
| `DIAG_DIRECTIVE_NOT_IMPLEMENTED` | A program-only key written in a directive (for example [`reflection.allow`](https://www.afterpack.dev/docs/config#reflection-allow)), or a redundant directive like `skip=false`. See [Which keys](https://www.afterpack.dev/docs/directives#what-you-can-set) for what a region can actually override. |
| `DIAG_DIRECTIVE_SOURCE_UNRESOLVED` | Info. A directive sits in a module whose position could not be mapped into the build output, so it was not applied. Move the marked code into an imported module. |
| `DIAG_DIRECTIVE_DANGLING_END` | A [`/* @afterpack end */`](https://www.afterpack.dev/docs/directives#what-you-can-set) with no open block above it. |
| `DIAG_DIRECTIVE_REGION_TO_FILE` | [`identifiers.globals.rename`](https://www.afterpack.dev/docs/config#identifiers-globals-rename) can't be scoped to a region, so a directive naming it is ignored and reported. |
| `DIAG_DIRECTIVE_COVERAGE_UNVERIFIED` | A bundled chunk carrying directives had [no decodable source map](https://www.afterpack.dev/docs/directives), so the marked regions couldn't be located in its bytes. |
| `DIAG_DIRECTIVE_TARGET_ELIMINATED` | Directives were located in a chunk's map but matched zero ranges. The marked code was tree-shaken, or the coordinates didn't line up. |
| `DIAG_ALREADY_OBFUSCATED` | The collected files already carry AfterPack's own obfuscated output from a prior run, matched against the [protection receipt](https://www.afterpack.dev/docs/cli#afterpack-verify-dir) by content hash. AfterPack output is not idempotent — rebuild from source first. |

### Cloud API

| Code | Meaning |
|---|---|
| `DIAG_INVALID_KEY` | Missing, malformed, or unknown [`key`](https://www.afterpack.dev/docs/config#key) (401). Check [`AFTERPACK_key`](https://www.afterpack.dev/docs/config#key), or issue a fresh key from the [dashboard](https://www.afterpack.dev/docs/dashboard/api-keys). |
| `DIAG_KEY_REVOKED` | The API key was revoked (401). |
| `DIAG_KEY_EXPIRED` | The API key expired (401). |
| `DIAG_KEY_OUT_OF_SCOPE` | The request IP is outside the key's allowed range (403). |
| `DIAG_MISSING_IP` | The request carried no client IP (400). |
| `DIAG_INVALID_MANIFEST` | Malformed multipart body, or a missing `batch` manifest part. |
| `DIAG_FILE_TOO_LARGE` | A single file exceeded the per-file byte ceiling (413). Split it, or exclude it with [`paths.exclude`](https://www.afterpack.dev/docs/config#paths-exclude). |
| `DIAG_ENTITLEMENT_LAPSED` | Subscription payment past due (402); update billing to keep building. |
| `DIAG_QUOTA_EXHAUSTED` | The build's byte total exceeds the [remaining allowance](https://www.afterpack.dev/docs/tiers), or the overage spend cap is reached. Checked once per build, before any file dispatches, so nothing already-protected degrades. Top up, upgrade, or raise the cap; the error carries the link. |
| `DIAG_RATE_LIMITED` | Rate limit exceeded (429); honour `Retry-After`. |
| `DIAG_RATE_CHECK_UNAVAILABLE` | The rate-limit check itself failed, so the request fails closed (503); retry. |
| `DIAG_BUILD_DEADLINE` | The wall-clock budget elapsed before every file started; the unfinished files are named. |
| `DIAG_ENGINE_FAILURE` | The cloud engine failed on a file. |

### Runtime reflection

AfterPack detects these [runtime-reflection](https://www.afterpack.dev/docs/config#reflection-allow) patterns: `functionToString`, `nameIntrospection`, `argumentsCallee`, `prototypeChain`, `decoratorMetadata` and `constructorIntrospection`. Each detection carries a code; which one depends on whether you acknowledged the pattern.

| Code | Meaning |
|---|---|
| `DIAG_REFLECTION_nameIntrospection_ACKNOWLEDGED` | Info. The pattern was detected and preserved because you acknowledged it. One code per pattern; the name in the middle is any of the patterns above. |
| `nameIntrospection` | Error. The pattern was detected and **not** acknowledged, so the build stops rather than shipping code whose runtime read would break. Acknowledge it with [`reflection.allow`](https://www.afterpack.dev/docs/config#reflection-allow), which also accepts `angular` and `nestjs`, or take the file out with [`paths.exclude`](https://www.afterpack.dev/docs/config#paths-exclude). |

> **Stray artifacts are caught by the audit**
>
> Shipping a stray [`.map`](https://www.afterpack.dev/docs/config#sourceMap-enabled) or an un-obfuscated sibling into your deploy tree is caught by [`npx afterpack@latest audit`](https://www.afterpack.dev/docs/audit), not by the build.
>
> If a code is missing or wrong, open an issue: [github.com/afterpack-dev/afterpack/issues](https://github.com/afterpack-dev/afterpack/issues).

Run with [`--diagnostics.level=all`](https://www.afterpack.dev/docs/config#diagnostics-level) for the full diagnostic stream on any build, rather than the default summary. In a plugin build the same switch is the [`diagnostics.level`](https://www.afterpack.dev/docs/config#diagnostics-level) option or [`AFTERPACK_diagnostics_level`](https://www.afterpack.dev/docs/config#diagnostics-level).

## Next

- [CLI reference](https://www.afterpack.dev/docs/cli): every flag the codes above reference.
- [Configuration](https://www.afterpack.dev/docs/config): the config keys these codes reference.
- [Directives](https://www.afterpack.dev/docs/directives): the full `@afterpack` grammar behind the directive codes above.
- [Best practices](https://www.afterpack.dev/docs/best-practices): the patterns that avoid these diagnostics in the first place.
- [Tiers](https://www.afterpack.dev/docs/tiers): what's Free vs. what needs a [`key`](https://www.afterpack.dev/docs/config#key).
