phalcon/cphalcon · error · Phalcon\Support\Helper\Json\Exceptions\JsonEncodeError

json_encode error: {message}

Error message

json_encode error: {message}

What it means

Phalcon\Support\Helper\Json\Encode wraps json_encode with throw-on-error semantics and rethrows any JsonException as Phalcon\Support\Helper\Json\Exceptions\JsonEncodeError ("json_encode error: {message}"). It fires when json_encode fails: malformed UTF-8 in strings ('Malformed UTF-8 characters, possibly incorrectly encoded'), NAN/INF floats, resources, arrays with mixed keys? no — primarily recursion ('Recursion detected') and depth over 512.

Source

Thrown at phalcon/Support/Helper/Json/Encode.zep:52

    use EncodeTrait;

    /**
     * @param int<1, max> $depth   Recursion depth.
     *
     * @throws JsonEncodeError if the JSON cannot be encoded.
     * @link https://www.php.net/manual/en/function.json-encode.php
     */
    public function __invoke(
        var data,
        int options = 79,
        int depth = 512
    ) -> string {
        var ex;

        try {
            return this->toEncode(data, options, depth);
        } catch JsonException, ex {
            throw new JsonEncodeError(ex->getMessage(), ex->getCode(), ex);
        }
    }
}

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Fix data encoding at the source: set UTF-8 on DB connections/files, or repair strings with mb_convert_encoding($v, 'UTF-8', 'UTF-8')
  2. Replace non-finite floats: is_finite($v) ? $v : null
  3. For circular graphs, implement JsonSerializable or unset back-references; raise $depth for legitimately deep structures
  4. As a last resort pass JSON_PARTIAL_OUTPUT_ON_ERROR via $options and accept placeholder output

Example fix

// before
$json = (new Encode())($row); // 'json_encode error: Malformed UTF-8 characters'

// after
array_walk_recursive($row, function (&$v) {
    if (is_string($v) && !mb_check_encoding($v, 'UTF-8')) {
        $v = mb_convert_encoding($v, 'UTF-8', 'UTF-8');
    } elseif (is_float($v) && !is_finite($v)) {
        $v = null;
    }
});
$json = (new Encode())($row);
Defensive patterns

Strategy: validation

Validate before calling

array_walk_recursive($data, function (&$value) {
    if (is_float($value) && !is_finite($value)) {
        $value = null; // NAN/INF are not JSON-encodable
    } elseif (is_string($value) && !mb_check_encoding($value, 'UTF-8')) {
        $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8');
    } elseif (is_resource($value)) {
        $value = null;
    }
});

$json = (new Encode())($data);

Type guard

function isJsonEncodableValue($value): bool
{
    if (is_float($value)) {
        return is_finite($value);
    }

    return !is_resource($value)
        && (!is_string($value) || mb_check_encoding($value, 'UTF-8'));
}

Try / catch

use Phalcon\Support\Helper\Json\Exceptions\JsonEncodeError;

try {
    $json = $encode($data);
} catch (JsonEncodeError $e) {
    // "json_encode error: Malformed UTF-8 characters..." / "Recursion detected"
    $logger->error($e->getMessage());
    $json = null;
}

Prevention

When it happens

Trigger: (new Encode())($row) where $row contains a latin1-bytes string from a misconfigured DB column; encoding a graph with circular references (parent/child objects cast to arrays); NAN/INF leaking from calculations; depth > 512.

Common situations: DB connections not set to UTF-8 producing invalid byte sequences; scientific/financial feeds delivering INF/NAN; entity graphs with back-references being serialized for caches or APIs.

Related errors


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