Diagnostics
The TypeSpec compiler uses the diagnostic API to report errors and warnings in the specification.
Best practices
- ❌ Avoid using throwto report errors. Any exceptions thrown in this manner will be perceived as bugs in your library by the user.
- ✅ Utilize the diagnostic API to report anticipated errors and warnings.
- ✅ Employ reportDiagnosticin a decorator,$onValidateor$onEmit
- ❌ Refrain from using reportDiagnosticin an accessor (a function intended to be used in another library or emitter). Refer to the section on collecting diagnostics for more information.
 
- ✅ Employ 
Diagnostic requirements
- Each diagnostic MUST have a code. The complete code is the library name followed by the declared code. (<lib-name>/<local-code>)
- Each diagnostic MUST have a severity. It can beerrororwarning. Errors cannot be suppressed.
- Each diagnostic MUST have at least one message. Using defaultas themessageIdwill make it the default selection.
- Each diagnostic message MAY have parameters to interpolate information into the message.
How to use
Declare the diagnostics you plan to report
import { createTypeSpecLibrary } from "@typespec/compiler";
// in lib.jsexport const $lib = createTypeSpecLibrary({  name: "@typespec/my-lib",  diagnostics: {    // Basic diagnostic with a fixed message    "no-array": {      severity: "error",      messages: {        default: `Array is not allowed in my-lib models.`,      },    },
    // Parameterized message    "duplicate-route": {      severity: "error",      messages: {        default: paramMessage`Route '${"path"}' is being referenced in 2 different operations.`,      },    },
    // Multiple messages    "duplicate-name": {      severity: "warning",      messages: {        default: paramMessage`Duplicate type name: '${"value"}'.`,        parameter: paramMessage`Duplicate parameter key: '${"value"}'.`,      },    },  },} as const);
// Re-export the helper functions to be able to just call them directly.export const { reportDiagnostic, createDiagnostic };This will represent three different diagnostics with the full names of:
- @typespec/my-lib/no-array
- @typespec/my-lib/duplicate-route
- @typespec/my-lib/duplicate-name
Report diagnostics
import { reportDiagnostic } from "./lib.js";
// Basic diagnostic with a fixed messagereportDiagnostic(program, {  code: "no-array",  target: diagnosticTarget,});
// Parameterized messagereportDiagnostic(program, {  code: "duplicate-route",  format: {path: "/foo"}  target: diagnosticTarget,});
// Multiple messagesreportDiagnostic(program, {  code: "duplicate-name",  messageId: "parameter",  format: {value: "$select"},  target: diagnosticTarget,});Collect diagnostics
When attempting to report a diagnostic in an accessor, a good practice is not to report the diagnostic to the program directly, but return a tuple to let the user decide what to do. This prevents duplicate diagnostics emitter if the accessor is called multiple times.
import { createDiagnosticCollector, Diagnostic } from "@typespec/compiler";
function getRoutes(): [Route, readonly Diagnostic] {  const diagnostics = createDiagnosticCollector();  diagnostics.add(    createDiagnostic(program, {      code: "no-array",      target: diagnosticTarget,    }),  );  const result = diagnostic.pipe(getParameters()); // to pipe diagnostics returned by `getParameters`  return diagnostics.wrap(routes);}or manually
import { Diagnostic } from "@typespec/compiler";
function getRoutes(): [Route, readonly Diagnostic] {  const diagnostics = [];  diagnostics.push(    createDiagnostic(program, {      code: "no-array",      target: diagnosticTarget,    }),  );  return [routes, diagnostics];}