phacility/phabricator · error · PhabricatorDocumentEngineParserException
Failed to "json_decode(...)" JSON document after successfull
Error message
Failed to "json_decode(...)" JSON document after successfully decoding it with "phutil_json_decode(...).
What it means
PhabricatorJSONDocumentEngine decodes twice: phutil_json_decode() first validates the JSON, then json_decode($raw_data, false) re-decodes it to preserve the object ('{}') vs list ('[]') distinction for rendering. This exception fires when the second decode yields a falsy PHP value — which happens for valid JSON whose root is a falsy literal: null, 0, false, "" or []. In other words it is a false-positive: the truthiness check (!$data) mistakes a valid falsy decode for a decoding failure.
Source
Thrown at src/applications/files/document/PhabricatorJSONDocumentEngine.php:43
if ($ref->isProbablyJSON()) {
return 1750;
}
return 500;
}
protected function newDocumentContent(PhabricatorDocumentRef $ref) {
$raw_data = $this->loadTextData($ref);
try {
$data = phutil_json_decode($raw_data);
// See T13635. "phutil_json_decode()" always turns JSON into a PHP array,
// and we lose the distinction between "{}" and "[]". This distinction is
// important when rendering a document.
$data = json_decode($raw_data, false);
if (!$data) {
throw new PhabricatorDocumentEngineParserException(
pht(
'Failed to "json_decode(...)" JSON document after successfully '.
'decoding it with "phutil_json_decode(...).'));
}
if (preg_match('/^\s*\[/', $raw_data)) {
$content = id(new PhutilJSON())->encodeAsList($data);
} else {
$content = id(new PhutilJSON())->encodeFormatted($data);
}
$message = null;
$content = PhabricatorSyntaxHighlighter::highlightWithLanguage(
'json',
$content);
} catch (PhutilJSONParserException $ex) {
$message = $this->newMessage(
pht(View on GitHub (pinned to 5720a38cfe)
Solutions
- Work around by giving the document a non-empty root: use an object with at least one member instead of a bare 'null', '0', or '[]'
- Patch the engine to detect failure with a strict null check plus json_last_error() instead of truthiness (the upstream class of fix)
- If rendering keeps failing, view/download the raw file instead of the formatted JSON view
Example fix
// before
$data = json_decode($raw_data, false);
if (!$data) {
throw new PhabricatorDocumentEngineParserException(
pht('Failed to "json_decode(...)" JSON document ...'));
}
// after
$data = json_decode($raw_data, false);
if ($data === null && json_last_error() !== JSON_ERROR_NONE) {
throw new PhabricatorDocumentEngineParserException(
pht('Failed to "json_decode(...)" JSON document ...'));
} Defensive patterns
Strategy: try-catch
Validate before calling
$decoded = json_decode($raw, false);
$valid = ($decoded !== null || json_last_error() === JSON_ERROR_NONE);
if (!$valid) {
// do not hand the document to the JSON engine
} Try / catch
catch PhabricatorDocumentEngineParserException specifically and fall back to plain-text rendering of the raw bytes; do not retry — the outcome is deterministic for a given document.
Prevention
- Emit JSON documents with an object root and at least one member
- Never test json_decode() results with truthiness; compare against null and json_last_error()
When it happens
Trigger: Uploading a .json file whose entire content is 'null', '0', 'false', '""' or '[]'. Each is valid JSON, so phutil_json_decode() succeeds, but json_decode() returns null/0/''/empty array and the if (!$data) guard throws.
Common situations: Machine-generated artifacts that legitimately contain a bare scalar or empty list (e.g. '[]' from a linter with no findings, 'null' from an API dump); minimal hand-written JSON test files.
Related errors
- No content engine can render this document.
- Configuration file is not properly formatted JSON. %s
- Expected JSON response from Duo.
- Use form-encoded data to submit parameters to Conduit endpoi
- The value for parameter '%s' is not valid JSON. All paramete
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/1a23750608dca2db.
Report an issue: GitHub.