“Content is not allowed in prolog”

Guide · Updated July 2026 · ~7 min read

You will meet this one asorg.xml.sax.SAXParseException: Content is not allowed in prolog in Java, or as “Data at the root level is invalid” in .NET. It nearly always means there is something before your XML declaration that you cannot see.

What the “prolog” actually is

The prolog is everything preceding the root element. The XML specification permits exactly four things there — the XML declaration, a doctype declaration, comments, and processing instructions:

<?xml version="1.0" encoding="UTF-8"?>   <!-- declaration -->
<!DOCTYPE catalog SYSTEM "catalog.dtd">  <!-- doctype    -->
<!-- a comment is fine here too -->
<catalog>                                <!-- root opens: prolog ends -->

Anything else — a single space, a newline, a stray character, a whole HTML page — makes the parser stop immediately. It is not being pedantic for its own sake: if a document does not start correctly, its encoding cannot be determined reliably, and every byte after that is guesswork.

Cause 1: an invisible UTF-8 BOM (most likely)

A byte-order mark is three bytes — EF BB BF — that some editors write at the start of “UTF-8” files. Notepad, Excel exports, and various Windows tools add it by default. Your editor hides it, your browser ignores it, and your XML parser refuses it.

Check for it directly. On macOS or Linux:

head -c 3 file.xml | xxd
# 00000000: efbb bf    ...   ← BOM present

In PowerShell on Windows:

Get-Content file.xml -Encoding Byte -TotalCount 3
# 239 187 191  ← BOM present

To remove it, re-save the file as “UTF-8 without BOM” — every serious editor offers this (VS Code shows the encoding in the status bar; Notepad++ has Encoding → Convert to UTF-8 without BOM). In code, strip it while reading:

// Java — the BOM is not stripped automatically
try (Reader r = new InputStreamReader(new BOMInputStream(in), StandardCharsets.UTF_8)) {
    document = builder.parse(new InputSource(r));
}
# Python — utf-8-sig removes a BOM if present, and is safe if it is not
with open("file.xml", encoding="utf-8-sig") as f:
    tree = ElementTree.parse(f)

The same three bytes break JSON parsers in exactly the same way — see the BOM trap in ourPython JSONDecodeError guide.

Cause 2: whitespace or a blank line before the declaration

The XML declaration must be the first bytes of the document. Not the first non-blank line — the first bytes. A leading newline is enough to fail:

<!-- ✗ Invalid: blank line before the declaration -->

<?xml version="1.0"?>
<catalog/>

<!-- ✓ Valid: declaration first, no leading whitespace -->
<?xml version="1.0"?>
<catalog/>

This bites hardest when XML is generated by a template. A PHP file with a blank line after?>, or a JSP with a newline before the declaration, emits that whitespace into the response. Trim the output, or move the declaration flush to the top of the template.

Cause 3: you received HTML instead of XML

If you are fetching the XML over HTTP, the “content” in the prolog may be an entire error page. A 404, a 500, or a login redirect returns HTML that begins<!DOCTYPE html>, and your parser dutifully reports that content is not allowed. Log the response body and status code before parsing — the same diagnosis as the JavaScript “Unexpected token <” error.

Cause 4: the declared encoding does not match the bytes

A file that says encoding="UTF-8" but was saved as Windows-1252 will fail as soon as a non-ASCII character appears — sometimes reported as an invalid-byte error, and sometimes surfacing here. Either save the file as real UTF-8, or declare the encoding it genuinely uses. Do not guess: mismatched encodings corrupt data silently even when they parse.

Cause 5: it is not the file you think it is

Worth ten seconds before a long debugging session. Open the file and look at the first few lines. Common surprises: an HTML page saved with an .xml extension, a Git LFS pointer stub instead of the real file, a truncated download, or a ZIP or gzip archive that was never decompressed. Compressed files begin with recognisable bytes —PK for ZIP, 1f 8b for gzip.

The same error in other stacks

Different wording, identical cause: something illegal sits before the root element.

Checklist

  1. Check the first three bytes for EF BB BF — remove the BOM if present.
  2. Make sure no space or newline precedes <?xml.
  3. Fetching over HTTP? Print the status and body — you may have an HTML error page.
  4. Confirm the declared encoding matches how the file was actually saved.
  5. Open the file and verify it is XML at all, not an archive or an LFS pointer.
  6. Then paste it into the XML validator to confirm it parses.

Frequently asked questions

What is the “prolog”?

Everything before the root element opens: the XML declaration, any doctype, comments, and processing instructions. Only those are legal there — no text, no stray bytes.

My file opens fine in a browser and an editor. Why does the parser reject it?

Browsers and editors silently skip a byte-order mark; strict XML parsers do not. An invisible BOM is the single most common cause of this error.

Why does the error say line 1 column 1?

Because the offending bytes sit at the very start of the document, before anything valid. That is a strong hint it is a BOM or leading whitespace rather than a markup mistake.

Does this mean my XML is invalid against its schema?

No. This is a well-formedness failure — the document did not parse at all, so schema validation never even started.

Keep reading