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) === false, i.e. the string is not valid UTF-8. The framework escapes string literals assuming UTF-8 (the default client encoding for the supported drivers); non-UTF-8 bytes cannot be safely embedded and would corrupt the literal, so it rejects them.

Solutions

  1. If the bytes are genuinely binary, escape with $binary=true: $connection->escape($value, true).
  2. Re-encode the string to UTF-8 before escaping: mb_convert_encoding($value, 'UTF-8', 'UTF-8') (or from the source encoding).
  3. Validate/repair encoding up front (mb_check_encoding) and drop or replace invalid sequences.
  4. Bind the value as a parameter so PDO handles encoding rather than escaping it inline.

Example fix

// before
$conn->escape($latin1String);

// after
$conn->escape(mb_convert_encoding($latin1String, 'UTF-8', 'Windows-1252'));
Defensive patterns

Strategy: validation

Validate before calling

if (is_string($value) && mb_check_encoding($value, 'UTF-8') === false) {
    $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8'); // drop invalid seqs
}
$escaped = $connection->escape($value);

Type guard

function isValidUtf8(string $value): bool {
    return mb_check_encoding($value, 'UTF-8');
}

Try / catch

try {
    $sql = $connection->escape($value);
} catch (\RuntimeException $e) {
    if (str_contains($e->getMessage(), 'UTF-8')) {
        $sql = $connection->escape($value, true); // treat as binary
    } else { throw $e; }
}

Prevention

When it happens

Trigger: Calling $connection->escape($s) where $s is a non-UTF-8 string (latin1/Windows-1252/raw bytes); concatenating output from a non-UTF-8 source (legacy API, gzip decode of binary, iconv without //IGNORE); binary data misrouted to the string branch.

Common situations: Importing legacy data with latin1 encoding; consuming an external feed that lies about charset; binary payloads that should have used the $binary flag.

Understand the failure class

Related errors


AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11). Data as JSON: /api/errors/0b4243f0bbaa065a. Report an issue: GitHub.

Appendix: 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 e0f6eb3518)