octobercms/october · error · ApplicationException

system::lang.media.invalid_path

Error message

system::lang.media.invalid_path

What it means

MediaLibrary::validatePath() rejects any path containing a Unicode category-C character (preg_match('/[\p{C}]/u')): control chars 0x00-0x1F and 0x7F-0x9F, format chars like zero-width space (U+200B), BOM (U+FEFF) and bidi/RTL override marks (U+200E, U+202E), plus surrogates and unassigned code points. These characters are invisible in listings but break rendering, sorting, matching, and remote storage keys, so the media library hard-rejects them.

Source

Thrown at modules/media/classes/MediaLibrary.php:500

     * @return string
     */
    public static function validatePath($path, $normalizeOnly = false): string
    {
        $path = str_replace('\\', '/', $path);
        $path = '/'.trim($path, '/');

        if ($normalizeOnly) {
            return $path;
        }

        // Reject paths that are not valid UTF-8
        if (!mb_check_encoding($path, 'UTF-8')) {
            throw new ApplicationException(Lang::get('system::lang.media.invalid_path_encoding', ['path' => mb_scrub($path)]));
        }

        // Reject control, format and other invisible characters
        if (preg_match('/[\p{C}]/u', $path)) {
            throw new ApplicationException(Lang::get('system::lang.media.invalid_path', compact('path')));
        }

        // Reject characters reserved by file systems and URLs
        if (preg_match('/[<>:"|?*]/', $path)) {
            throw new ApplicationException(Lang::get('system::lang.media.invalid_path', compact('path')));
        }

        $regexDirectorySeparator = preg_quote('/', '#');
        $regexDot = preg_quote('.', '#');
        $regex = [
            // Beginning of path
            '(^'.$regexDot.'+?'.$regexDirectorySeparator.')',

            // Middle of path
            '('.$regexDirectorySeparator.$regexDot.'+?'.$regexDirectorySeparator.')',

            // End of path
            '('.$regexDirectorySeparator.$regexDot.'+?$)',

View on GitHub (pinned to b608633a7e)

Solutions

  1. Strip category-C characters before calling the API: $path = preg_replace('/\p{C}/u', '', $path);
  2. For user-supplied names, sanitize aggressively on input (slugify or transliterate) instead of accepting raw pasted strings
  3. Paste the path into a hex viewer or use bin2hex() on the suspect segment to identify the exact invisible code point, then rename the file

Example fix

// before
$clean = MediaLibrary::validatePath($raw); // rejects zero-width chars

// after
$raw = preg_replace('/\p{C}/u', '', $raw);
$clean = MediaLibrary::validatePath($raw);
Defensive patterns

Strategy: validation

Validate before calling

$path = preg_replace('/\p{C}/u', '', $path); // strip control/format/invisible chars
$clean = MediaLibrary::validatePath($path);

Type guard

function hasInvisiblePathChars(string $path): bool {
    return (bool) preg_match('/\p{C}/u', $path);
}

Prevention

When it happens

Trigger: Filenames copy-pasted from web pages, PDFs, or word processors that embed zero-width characters; crafted names using RTL-override to disguise the real extension; paths containing literal tab/newline; a UTF-8 BOM prefixed to the first segment.

Common situations: Bulk imports from CSV/Excel with unclean data; user complaints that a file 'looks fine' but the media manager rejects it; security scanners probing with bidi tricks.

Related errors


AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21). Data as JSON: /api/errors/ccd3b49129f0c598. Report an issue: GitHub.