phalcon/cphalcon · error · \JsonException

json_last_error_msg()

Error message

json_last_error_msg()

What it means

The JSON encode helper (Phalcon\Support\Helper\Json\Encode, via EncodeTrait::toEncode) wraps json_encode and converts failures into a native \JsonException carrying json_last_error_msg() — typical messages: 'Double INF or NaN did not resolve to a finite number', 'Recursion detected', 'Malformed UTF-8 characters, possibly incorrectly encoded' (phalcon/Traits/Support/Helper/Json/EncodeTrait.zep:55).

Source

Thrown at phalcon/Traits/Support/Helper/Json/EncodeTrait.zep:55

        var encoded, error, message;

        /**
         * Need to clear the json_last_error() before the code below
         */
        let encoded = json_encode(null),
            encoded = json_encode(data, options, depth),
            error   = json_last_error(),
            message = json_last_error_msg();

        /**
         * When JSON_THROW_ON_ERROR is set, json_encode() has already raised a
         * native \JsonException above; otherwise the error is surfaced the
         * same way here.
         */
        if (JSON_ERROR_NONE !== error) {
            json_encode(null);

            throw new \JsonException(message, error);
        }

        return (string) encoded;
    }
}

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Sanitize first: normalize INF/NAN to 0/null, and re-encode strings with mb_convert_encoding($s, 'UTF-8', 'UTF-8') or filter invalid bytes.
  2. Pass JSON_INVALID_UTF8_SUBSTITUTE in the options bitmask to substitute bad bytes instead of failing.
  3. Catch \JsonException at the boundary and degrade gracefully (skip the cache entry, return an error payload) instead of a 500.

Example fix

// before
$json = (new Encode())->__invoke(['score' => log(0)]); // -INF -> JsonException

// after
$payload = ['score' => is_finite($score) ? $score : 0];
$json    = (new Encode())->__invoke($payload, JSON_INVALID_UTF8_SUBSTITUTE);
Defensive patterns

Strategy: try-catch

Try / catch

try {
    $json = (new Encode())->__invoke($payload, JSON_INVALID_UTF8_SUBSTITUTE);
} catch (\JsonException $e) {
    $logger->error('JSON encode failed: ' . $e->getMessage());
    $json = null; // skip the cache entry / return error payload
}

Prevention

When it happens

Trigger: Encode::__invoke($data) on structures containing INF/NAN floats, recursive arrays/objects, resources, or strings with invalid UTF-8 (binary from a DB, latin1 data read as UTF-8).

Common situations: Encoding computed floats that hit division-by-zero yielding INF; cache layers storing layered arrays that reference themselves; DB rows in the wrong charset; binary blobs accidentally placed in an API payload.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/49783e9374a5f378. Report an issue: GitHub.