Skip to content

XmlReaderTask fails on an empty file and silently emits an empty DOMDocument on invalid XML #202

Description

@njoubert-cleverage

Description

XmlReaderTask (through CleverAge\ProcessBundle\Filesystem\XmlFile::read()) does not handle bad input files:

  • Empty file: the task crashes with a low-level ValueError: SplFileObject::fread(): Argument #1 ($length) must be greater than 0.
  • Invalid XML: the result of DOMDocument::loadXML() is ignored. Only a PHP warning is raised, and an empty \DOMDocument (documentElement = null, no child nodes) is passed to the next tasks. In debug mode the Symfony error handler turns the warning into an exception, so the process fails; without debug (production), the process goes on silently with an empty document.

Reproduction

clever_age_process:
    configurations:
        demo.xml_reader_invalid:
            tasks:
                read:
                    service: '@CleverAge\ProcessBundle\Task\File\Xml\XmlReaderTask'
                    options:
                        file_path: '{{ file_path }}'
                    outputs: [dump]
                dump:
                    service: '@CleverAge\ProcessBundle\Task\Debug\DebugTask'
printf '' > var/data/empty.xml
printf '<root><a>1</a>' > var/data/invalid.xml
bin/console cleverage:process:execute demo.xml_reader_invalid -c file_path:"'/var/www/var/data/empty.xml'"
bin/console cleverage:process:execute --no-debug demo.xml_reader_invalid -c file_path:"'/var/www/var/data/invalid.xml'"

Empty file:

CRITICAL  [cleverage_process_task] SplFileObject::fread(): Argument #1 ($length) must be greater than 0
In XmlFile.php line 33:
  Process demo.xml_reader_invalid has failed during process read with message
  : 'SplFileObject::fread(): Argument #1 ($length) must be greater than 0'.

Invalid XML (--no-debug): the process does not fail, and the dumped document is empty:

ERROR     [php] Warning: DOMDocument::loadXML(): Premature end of data in tag root line 1 in Entity, line: 1
  +childNodes: DOMNodeList {
    +length: 0
  +documentElement: null

Tested on main (c1a2804), PHP 8.5, Symfony 7.4.

Cause

In XmlFile::read():

  • the file size is passed to fread() without a check, and fread(0) throws a ValueError (L33);
  • the return value of $dom->loadXML() is ignored (L35), and libxml errors are only reported as PHP warnings.

Proposed fix

  • an empty file throws an explicit \UnexpectedValueException('XML file "<path>" is empty');
  • loadXML() runs with libxml_use_internal_errors(true); the collected libxml errors are cleared and the previous setting is restored;
  • if the load fails, or libxml reports an error or a fatal error, an \UnexpectedValueException('Invalid XML in file "<path>": <libxml message> (line L, column C); ...') is thrown; libxml warnings are still tolerated;
  • update the XmlReaderTask reference documentation (Notes), add unit tests for XmlFile.

Requirements

  • Documentation updates
    • Reference
    • Cookbooks
    • Changelog
  • Unit tests

Breaking changes

Bug fix: XmlReaderTask now throws an \UnexpectedValueException when the XML is invalid, instead of passing an empty or partial \DOMDocument to the next tasks with only a PHP warning. This includes XML that parses but has libxml errors, such as an undefined namespace prefix (<root><x:a/></root>), which used to give a partial document. An empty file now throws an \UnexpectedValueException instead of a \ValueError. Processes relying on the silent empty document (e.g. in production, without the Symfony debug error handler) will now fail at the reader task: use error_strategy to handle these files.

Activity

  1. added a commit that references this issue on Sep 28, 2026
  2. added a commit that references this issue on Sep 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions