# 2200N — invalid_xml_content

> Source-backed reference for PostgreSQL SQLSTATE 2200N.
---

# 2200N

## At a glance {#at-a-glance}
This member covers invalid XML content. PostgreSQL 18.6’s core XML parser has a content-mode declaration guard and content-parse guards that report 2200N; the original XML option determines whether a document parse failure is instead reported as 2200M.

<!-- BEGIN SQLSTATE FACTS: generated by scripts/generate.py; do not edit -->

| Field | Value |
| --- | --- |
| SQLSTATE | `2200N` |
| Condition | `invalid_xml_content` |
| Status | `active` |
| Known present by | `8.3.0` |
| Locked snapshots | `9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3` |
| Macros | `ERRCODE_INVALID_XML_CONTENT` |
| Aliases | `—` |

<!-- source facts: data/errcodes/2200N.json -->
<!-- END SQLSTATE FACTS -->

## Meaning {#meaning}
This member names invalid XML content at the parser’s CONTENT boundary. In content mode, an invalid XML declaration raises `invalid XML content: invalid XML declaration` with a detail produced by `errdetail_for_xml_code(res_code)`. A failed balanced-content parse raises `invalid XML content`; if CONTENT input contains a DOCTYPE and is parsed as a document, the failed document parse still uses the original option to select 2200N. The same failed parser call uses 2200M when the original option was DOCUMENT. The declaration branch calls `errsave` and the content branches call `xml_errsave`: with an `ErrorSaveContext` these errors are saved and returned to the caller, while an ordinary context throws `ERROR`; that distinction is separate from the dynamic DETAIL text.

## Messages {#messages}

The cited branches raise `ERROR` with primary `invalid XML content: invalid XML declaration` for the declaration guard, with dynamic DETAIL from `errdetail_for_xml_code(res_code)`, or primary `invalid XML content` for the later content/document parse failures. The declaration variant’s evidence template is `dynamic errdetail_for_xml_code(res_code)`, not a fixed DETAIL string. No fixed universal DETAIL or HINT should be invented for those parser failures. 2200L is the outer document-option wrapper, while 2200S and 2200T identify comment and processing-instruction syntax.

## Diagnosis {#diagnosis}
Read the complete parser message and the XML fragment or value it identifies. Check element names, character data, encoding, and the operation’s expected XML level. Follow a reported 2200L, 2200M, 2200S, or 2200T directly when the server emits one of those codes; do not choose 2200N from the word “invalid” alone.

## Response {#response}
Correct the XML content at the element, character, or encoding boundary named by the diagnostic, and retain the actual code when validating the fix.

When this branch raises `ERROR`, an explicit transaction must first be recovered with `ROLLBACK` or `ROLLBACK TO SAVEPOINT` for a savepoint established before the statement; in autocommit, retry only the corrected action after the failed statement completes. See the [transaction and retry guide](../guides/) for this boundary rule.

## Versions {#versions}
The locked catalogue records this condition from 8.3.0; fixed source coverage is PostgreSQL 18.6.

## Related {#related}
[`2200L`](../2200l/), [`2200S`](../2200s/), [`2200T`](../2200t/)

## Sources {#sources}
Fixed core source: [`src/backend/utils/adt/xml.c#L1780-1894`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/xml.c#L1780-L1894). The shared [`xml_errsave`/`errsave` helper](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/xml.c#L2047-L2082) defines the soft-error versus ordinary-throw behavior. The structured [evidence record](../data/evidence/2200n.json) retains the declaration and content-parse guards, dynamic-detail boundary, and scope limits. Core availability depends on `USE_LIBXML`; no natural XML case was run for this page.
