---
title: "Error reference · tabnas"
description: "Every error code the tabnas engine and its grammar plugins can raise, what it means, and where it is declared."
source: "https://tabnas.dev/errors/"
---

# The tabnas error reference

46 error codes in three namespaces: 11 raised by the engine itself, 33 declared by individual grammar plugins, and 4 returned by the C shared libraries. A tabnas diagnostic always carries a `code`, and the code (never the message text) is what stays the same across the TypeScript and Go runtimes. Match on it.

Generated from the engine's [`schema/error-codes.json`](https://github.com/tabnas/parser/blob/main/schema/error-codes.json) and from each plugin's `tabnas.plugin.json` descriptor: nothing on this page is hand-listed. Engine 0.12.9. Machine-readable: [`/versions.json`](https://tabnas.dev/versions.json).

## Engine codes

Raised by the parsing engine itself, so any grammar can produce them. `{placeholders}` in a message are filled from the failing token and its details.

| Code | Message |
| --- | --- |
| [`cancel`](https://tabnas.dev/errors/cancel/) | `parse cancelled` |
| [`end_of_source`](https://tabnas.dev/errors/end_of_source/) | `unexpected end of source` |
| [`internal`](https://tabnas.dev/errors/internal/) Go only | `internal error: {src}` |
| [`invalid_ascii`](https://tabnas.dev/errors/invalid_ascii/) | `invalid ascii escape: {src}` |
| [`invalid_unicode`](https://tabnas.dev/errors/invalid_unicode/) | `invalid unicode escape: {src}` |
| [`unexpected`](https://tabnas.dev/errors/unexpected/) | `unexpected character(s): {src}` |
| [`unknown`](https://tabnas.dev/errors/unknown/) | `unknown error: {code}` |
| [`unknown_rule`](https://tabnas.dev/errors/unknown_rule/) | `unknown rule: {rulename}` |
| [`unprintable`](https://tabnas.dev/errors/unprintable/) | `unprintable character: {src}` |
| [`unterminated_comment`](https://tabnas.dev/errors/unterminated_comment/) | `unterminated comment: {src}` |
| [`unterminated_string`](https://tabnas.dev/errors/unterminated_string/) | `unterminated string: {src}` |

## Plugin codes

Declared by one grammar plugin, in its own error catalogue. A plugin raises these in addition to the engine codes above.

| Code | Declared by |
| --- | --- |
| [`bad_entity_ref`](https://tabnas.dev/errors/bad_entity_ref/) | `@tabnas/xml` |
| [`cdata_terminator_in_text`](https://tabnas.dev/errors/cdata_terminator_in_text/) | `@tabnas/xml` |
| [`comment_double_dash`](https://tabnas.dev/errors/comment_double_dash/) | `@tabnas/xml` |
| [`csv_extra_field`](https://tabnas.dev/errors/csv_extra_field/) | `@tabnas/csv` |
| [`csv_missing_field`](https://tabnas.dev/errors/csv_missing_field/) | `@tabnas/csv` |
| [`duplicate_attribute`](https://tabnas.dev/errors/duplicate_attribute/) | `@tabnas/xml` |
| [`duplicate_section`](https://tabnas.dev/errors/duplicate_section/) | `@tabnas/ini` |
| [`external_entity_in_attr`](https://tabnas.dev/errors/external_entity_in_attr/) | `@tabnas/xml` |
| [`invalid_namespace_uri`](https://tabnas.dev/errors/invalid_namespace_uri/) | `@tabnas/xml` |
| [`invalid_xml_char`](https://tabnas.dev/errors/invalid_xml_char/) | `@tabnas/xml` |
| [`json5_empty`](https://tabnas.dev/errors/json5_empty/) | `@tabnas/json5` |
| [`json5_no_value`](https://tabnas.dev/errors/json5_no_value/) | `@tabnas/json5` |
| [`lt_in_attr_value`](https://tabnas.dev/errors/lt_in_attr_value/) | `@tabnas/xml` |
| [`multisource_cycle`](https://tabnas.dev/errors/multisource_cycle/) | `@tabnas/multisource` |
| [`multisource_not_found`](https://tabnas.dev/errors/multisource_not_found/) | `@tabnas/multisource` |
| [`pi_target_invalid`](https://tabnas.dev/errors/pi_target_invalid/) | `@tabnas/xml` |
| [`reserved_namespace`](https://tabnas.dev/errors/reserved_namespace/) | `@tabnas/xml` |
| [`text_at_top_level`](https://tabnas.dev/errors/text_at_top_level/) | `@tabnas/xml` |
| [`unbound_prefix`](https://tabnas.dev/errors/unbound_prefix/) | `@tabnas/xml` |
| [`undeclared_entity`](https://tabnas.dev/errors/undeclared_entity/) | `@tabnas/xml` |
| [`unparsed_entity_ref`](https://tabnas.dev/errors/unparsed_entity_ref/) | `@tabnas/xml` |
| [`unterminated_cdata`](https://tabnas.dev/errors/unterminated_cdata/) | `@tabnas/xml` |
| [`unterminated_comment`](https://tabnas.dev/errors/unterminated_comment/) | `@tabnas/xml` |
| [`unterminated_doctype`](https://tabnas.dev/errors/unterminated_doctype/) | `@tabnas/xml` |
| [`unterminated_pi`](https://tabnas.dev/errors/unterminated_pi/) | `@tabnas/xml` |
| [`unterminated_section`](https://tabnas.dev/errors/unterminated_section/) | `@tabnas/ini` |
| [`xml_invalid_tag`](https://tabnas.dev/errors/xml_invalid_tag/) | `@tabnas/xml` |
| [`xml_mismatched_tag`](https://tabnas.dev/errors/xml_mismatched_tag/) | `@tabnas/xml` |
| [`zon_char`](https://tabnas.dev/errors/zon_char/) | `@tabnas/zon` |
| [`zon_doc_comment`](https://tabnas.dev/errors/zon_doc_comment/) | `@tabnas/zon` |
| [`zon_dup_field`](https://tabnas.dev/errors/zon_dup_field/) | `@tabnas/zon` |
| [`zon_ident`](https://tabnas.dev/errors/zon_ident/) | `@tabnas/zon` |
| [`zon_number`](https://tabnas.dev/errors/zon_number/) | `@tabnas/zon` |

## C ABI codes

A different namespace, and worth reading as one. These are not parse diagnostics: they come back in the JSON reply of a `libtabnas<format>` shared library, and they describe the _call_ (a bad pointer, a handle you already freed) rather than the input you passed. All 28 libraries return the same four, because the ABI is uniform by decision (`v1`).

The distinction that actually costs people time: a library returns `{"ok":true,"accept":false}` when your input is outside the format. That is an **answer**, not an error, and it carries no code from this table. A code from this table means the call itself was wrong.

| Code | Returned by |
| --- | --- |
| [`grammar`](https://tabnas.dev/errors/grammar/) | every clib (28) |
| [`handle`](https://tabnas.dev/errors/handle/) | every clib (28) |
| [`internal`](https://tabnas.dev/errors/internal/) | every clib (28) |
| [`usage`](https://tabnas.dev/errors/usage/) | every clib (28) |

## Reading a diagnostic

Every failing parse produces the same structured object: the same fields in both runtimes, described by the engine's [`diagnostic.schema.json`](https://github.com/tabnas/parser/blob/main/schema/diagnostic.schema.json). The fields worth reading first are `code` (what went wrong), `row`/`col` (where), `expected` (which tokens would have matched) and `ruleStack` (how the parser got there).

The [agents guide](https://tabnas.dev/agents/) covers using these while iterating on a grammar, and the [`debug-parse` skill](https://tabnas.dev/skills/) is the same workflow packaged for an agent.
