---
title: "Structured Diagnostics"
description: "ctx.diagnostics is a thin layer over nostics for author-defined coded diagnostics, each with a stable code, docs URL, and structured payload."
canonical_url: "https://devfra.me/guide/diagnostics"
---
# Structured Diagnostics

> ctx.diagnostics is a thin layer over nostics for author-defined coded diagnostics, each with a stable code, docs URL, and structured payload.

`ctx.diagnostics` is a thin layer over [`nostics`](https://www.npmjs.com/package/nostics) for author-defined coded diagnostics, each with a stable code, docs URL, and structured payload.

| Surface                                                  | Purpose                                                          | Example                              |
| -------------------------------------------------------- | ---------------------------------------------------------------- | ------------------------------------ |
| `ctx.diagnostics`                                        | Coded errors and warnings emitted from node-side code            | `MYP0001: Plugin foo not configured` |
| [`ctx.messages`](https://devtools.vite.dev/kit/messages) | Free-form, user-facing notifications shown in the Messages panel | `'Audit complete: 3 issues found'`   |

## Shape

```ts
interface DevframeDiagnosticsHost {
  /** Proxy-backed lookup over every registered code. */
  readonly logger: Record<string, DiagnosticHandle>

  /** Register additional diagnostic definitions. */
  register: (definitions: Record<string, unknown>) => void

  /** Build a typed diagnostics object with devframe's ANSI reporter pre-wired. */
  defineDiagnostics: typeof defineDiagnostics
}
```

The diagnostics host ships pre-seeded with devframe's `DF*` codes plus the host framework's own (`DTK*`, etc.); call `register()` to add your own.

## Register your own codes

```ts
export function MyPlugin(): PluginWithDevTools {
  return {
    name: 'my-plugin',
    devtools: {
      setup(ctx) {
        const myDiagnostics = ctx.diagnostics.defineDiagnostics({
          docsBase: 'https://example.com/errors',
          codes: {
            MYP0001: {
              why: (p: { name: string }) => `Plugin "${p.name}" is not configured`,
              fix: 'Add the plugin to your `vite.config.ts` and pass an options object.',
            },
            MYP0002: {
              why: 'Cache directory missing; running cold.',
            },
          },
        })

        ctx.diagnostics.register(myDiagnostics)

        // Emit through the host framework's shared reporter:
        myDiagnostics.MYP0002()
      },
    },
  }
}
```

## Code conventions

Codes are a 4-letter prefix + 4-digit number (e.g. `MYP0001`); pick one distinctive enough to avoid collisions.

`DF` belongs to `devframe` itself; the `@vitejs/devtools` packages own `DTK`, `RDDT`, and `VDT`. The prefixes in use are listed in the [Node-Side API reference](https://devfra.me/references/node-api#diagnostic-code-prefixes).

A definition takes a `why` (message) and optional `fix` (resolution), string or function; `docsBase` auto-attaches the URL to each diagnostic.

## Emit a diagnostic

Each registered code becomes a callable `DiagnosticHandle`: call it to report, or `throw` to raise.

```ts
// Throw: control flow stops here
throw myDiagnostics.MYP0001({ name: 'foo' })

// Report without throwing (default console method: `warn`)
myDiagnostics.MYP0002()

// Override the console method per call
myDiagnostics.MYP0002({}, { method: 'error' })

// Attach a `cause`: merged into the params object
throw myDiagnostics.MYP0001({ name: 'foo', cause: error })
```

The returned `Diagnostic` extends `Error`, so `throw` narrows following lines as unreachable.

## Typed handle reference

`ctx.diagnostics.logger` is loosely typed over all registered codes; for autocompletion, keep and call the typed result of `defineDiagnostics()` directly, whose pre-wired ANSI reporter gives it and the lookup identical output.

## Document your codes

Pair each code with a documentation page:

```
docs/errors/
  index.md            # Table of all codes
  MYP0001.md          # One page per code
  MYP0002.md
```

Each page covers message, cause, example, and fix; see any [DF code page](https://devfra.me/errors/) for the template.

## When to use what

**`ctx.diagnostics`** covers coded, docs-backed conditions, targeting tool authors and CI; **`ctx.messages`** covers user-facing UI activity, targeting the human at the panel.


## Sitemap

See the full [sitemap](https://devfra.me/sitemap.md) for all pages.
