laravel/framework · error · RuntimeException

Strings with invalid UTF-8 byte sequences cannot be escaped.

Error message

Strings with invalid UTF-8 byte sequences cannot be escaped.

What it means

Thrown by Connection::escape() when preg_match('//u', $value) fails, i.e. the string is not valid UTF-8. The driver-level quote()/escapeString assumes a valid encoding, so the framework bails rather than emit a malformed literal that could be misinterpreted by the server.

Source

Thrown at src/Illuminate/Database/Connection.php:1186

    public function escape($value, $binary = false)
    {
        if ($value === null) {
            return 'null';
        } elseif ($binary) {
            return $this->escapeBinary($value);
        } elseif (is_int($value) || is_float($value)) {
            return (string) $value;
        } elseif (is_bool($value)) {
            return $this->escapeBool($value);
        } elseif (is_array($value)) {
            throw new RuntimeException('The database connection does not support escaping arrays.');
        } else {
            if (str_contains($value, "\00")) {
                throw new RuntimeException('Strings with null bytes cannot be escaped. Use the binary escape option.');
            }

            if (preg_match('//u', $value) === false) {
                throw new RuntimeException('Strings with invalid UTF-8 byte sequences cannot be escaped.');
            }

            return $this->escapeString($value);
        }
    }

    /**
     * Escape a string value for safe SQL embedding.
     *
     * @param  string  $value
     * @return string
     */
    protected function escapeString($value)
    {
        return $this->getReadPdo()->quote($value);
    }

    /**

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Fix the source encoding: convert before escaping with mb_convert_encoding($value, 'UTF-8', 'UTF-8') to drop invalid bytes, or from the real source encoding.
  2. If the data is genuinely binary, use $connection->escape($value, binary: true).
  3. Validate and sanitize input with iconv('UTF-8', 'UTF-8//IGNORE', $value) before escaping.
  4. Bind the value as a parameter instead of escaping it inline, when the driver accepts the raw bytes.

Example fix

// before
$sql = '... where name = '.$conn->escape($dirtyLatin1);

// after
$clean = mb_convert_encoding($dirtyLatin1, 'UTF-8', 'UTF-8');
$sql = '... where name = '.$conn->escape($clean);
Defensive patterns

Strategy: validation

Validate before calling

if (is_string($value) && preg_match('//u', $value) === false) {
    $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8');
    // or, if truly binary: $connection->escape($value, binary: true)
}
$literal = $connection->escape($value);

Type guard

function isValidUtf8(string $v): bool {
    return preg_match('//u', $v) === 1;
}

Prevention

When it happens

Trigger: Calling $connection->escape($string) on a string with invalid UTF-8 byte sequences (truncated multibyte char, legacy Latin-1 / ISO-8859-1 text, binary garbage masquerading as text).

Common situations: Importing legacy non-UTF-8 data; scraping HTML declared as a different encoding; reading a partial multibyte sequence from a stream; concatenating raw bytes from an external API.

Related errors


AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06). Data as JSON: /data/errors/0b4243f0bbaa065a.json. Report an issue: GitHub.