惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
Y
Y Combinator Blog
博客园_首页
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
阮一峰的网络日志
阮一峰的网络日志
Hugging Face - Blog
Hugging Face - Blog
宝玉的分享
宝玉的分享
B
Blog
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
WordPress大学
WordPress大学
L
LangChain Blog
爱范儿
爱范儿
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Proofpoint News Feed
Blog — PlanetScale
Blog — PlanetScale
C
Check Point Blog
博客园 - 聂微东
云风的 BLOG
云风的 BLOG
Microsoft Security Blog
Microsoft Security Blog
博客园 - 叶小钗
酷 壳 – CoolShell
酷 壳 – CoolShell
H
Help Net Security

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
PostgreSQL 2200N Error: Causes and Solutions Complete Guide
umzzil nng · 2026-06-15 · via DEV Community

umzzil nng

PostgreSQL Error 2200N: invalid xml content

PostgreSQL error 2200N: invalid xml content occurs when you attempt to insert or process malformed XML data into an XML type column or pass invalid XML to XML-related functions. PostgreSQL strictly validates XML data against the W3C XML standard, and any deviation — from mismatched tags to illegal characters — triggers this error. It most commonly appears when ingesting XML from external APIs, legacy systems, or dynamically building XML strings in application code.


Top 3 Causes & SQL Examples

1. Mismatched or Improperly Nested Tags

XML requires every opening tag to have a matching closing tag in the correct order.

-- This will fail: tags are improperly nested
INSERT INTO orders (id, xml_data)
VALUES (1, XMLPARSE(DOCUMENT '<order><item>Apple</order></item>'));
-- ERROR:  invalid xml content

-- Correct version
INSERT INTO orders (id, xml_data)
VALUES (1, XMLPARSE(DOCUMENT '<order><item>Apple</item></order>'));

2. Unescaped Special Characters

Characters like &, <, and > must be escaped as XML entities (&amp;, &lt;, &gt;). Passing them raw inside XML text nodes will break parsing immediately.

-- This will fail: unescaped ampersand
SELECT XMLPARSE(DOCUMENT '<company><name>AT&T</name></company>');
-- ERROR:  invalid xml content

-- Fix 1: Use xmlelement() — it escapes automatically
SELECT xmlelement(name company,
           xmlelement(name name, 'AT&T')
       );
-- Result: <company><name>AT&amp;T</name></company>

-- Fix 2: Manual escape before parsing
SELECT XMLPARSE(DOCUMENT
    replace(raw_xml, '&', '&amp;')
)
FROM staging_table
WHERE id = 1;

3. Multiple Root Elements or Missing Root

A valid XML document must have exactly one root element. Concatenating XML fragments without a wrapper is a very common mistake.

-- This will fail: two root elements
SELECT XMLPARSE(DOCUMENT '<item>A</item><item>B</item>');
-- ERROR:  invalid xml content

-- Fix: wrap fragments in a single root
SELECT XMLPARSE(DOCUMENT '<items><item>A</item><item>B</item></items>');

-- Safely aggregate multiple rows into one XML document
WITH fragments AS (
    SELECT '<item>' || product_name || '</item>' AS frag
    FROM products
    WHERE category = 'fruit'
)
SELECT XMLPARSE(DOCUMENT
    '<items>' || string_agg(frag, '') || '</items>'
)
FROM fragments;


Quick Fix Solutions

Create a validation helper function to identify bad rows before they cause errors in production:

-- Validation helper function
CREATE OR REPLACE FUNCTION is_valid_xml(p_text TEXT)
RETURNS BOOLEAN AS $$
BEGIN
    PERFORM XMLPARSE(DOCUMENT p_text);
    RETURN TRUE;
EXCEPTION
    WHEN invalid_xml_content THEN
        RETURN FALSE;
END;
$$ LANGUAGE plpgsql;

-- Find all invalid XML rows in a staging table
SELECT id, raw_xml
FROM staging_xml_data
WHERE is_valid_xml(raw_xml) = FALSE;

-- Safe load: only move valid rows to production
INSERT INTO production_table (id, xml_data)
SELECT id, XMLPARSE(DOCUMENT raw_xml)
FROM staging_xml_data
WHERE is_valid_xml(raw_xml) = TRUE;


Prevention Tips

1. Use PostgreSQL's built-in XML functions instead of string concatenation.
Functions like xmlelement(), xmlforest(), and xmlagg() automatically escape special characters and guarantee well-formed output, eliminating the most common source of this error.

-- Preferred: built-in functions handle escaping for you
SELECT xmlelement(name report,
           xmlattributes(NOW() AS generated_at),
           xmlforest(
               customer_name AS customer,
               total_amount  AS total
           )
       )
FROM orders;

2. Validate XML at the staging layer before promoting to production.
Always land raw XML into a TEXT staging column first, run is_valid_xml() batch checks, and only promote verified data to your XML typed production columns. This two-stage pipeline prevents invalid data from ever reaching live tables and makes debugging far easier.


Related Errors

  • 2200M (invalid XML document) — Similar error; the document structure is recognized but content violates XML rules.
  • 22000 (data exception) — Parent error class for all XML and data-type violations.
  • 42804 (datatype mismatch) — Raised when inserting TEXT into an XML column without an explicit cast.

📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.