laravel/framework · error · ViteException

The font manifest at [{$path}] is not valid JSON.

Error message

The font manifest at [{$path}] is not valid JSON.

What it means

ViteFonts::manifest() reads a font manifest JSON file (path supplied by the developer) and throws ViteException if json_decode reports an error. This protects callers from silently feeding malformed data into the CSS-resolution logic. Only triggered when the file exists and is non-JSON.

Source

Thrown at src/Illuminate/Foundation/ViteFonts.php:57

     *
     * @throws \Illuminate\Foundation\ViteException
     */
    protected function readManifest(string $path)
    {
        if (isset(static::$manifests[$path])) {
            return static::$manifests[$path];
        }

        if (! is_file($path)) {
            return null;
        }

        $contents = file_get_contents($path);

        $manifest = json_decode($contents, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new ViteException("The font manifest at [{$path}] is not valid JSON.");
        }

        return static::$manifests[$path] = $manifest;
    }

    /**
     * Resolve the CSS content from the manifest.
     *
     * @param  array<string, mixed>  $manifest
     * @param  list<string>|null  $aliases
     * @param  string  $buildDirectory
     * @return string
     *
     * @throws \Illuminate\Foundation\ViteException
     */
    public function resolveStyleContent(array $manifest, ?array $aliases, string $buildDirectory)
    {
        $style = $manifest['style'] ?? null;

View on GitHub (pinned to e0f6eb3518)

Solutions

  1. Regenerate the font manifest by rerunning the Vite build / font plugin pipeline.
  2. Validate the file with a JSON linter (jq . <path>) to find the syntax error.
  3. Confirm the configured path points to the actual generated manifest, not a staging or template file.
  4. Upgrade or downgrade the Vite font plugin to a version whose output this ViteFonts version understands.

Example fix

// before — manifest file contains a stray trailing comma
{ "family": "Inter", }

// after
{ "family": "Inter" }
Defensive patterns

Strategy: validation

Validate before calling

$path = config('vite.fonts_manifest_path');
if ($path && is_file($path)) {
    json_decode(file_get_contents($path), true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new RuntimeException('Font manifest invalid JSON: '.json_last_error_msg());
    }
}

Type guard

function fontManifestIsValidJson(string $path): bool {
    if (! is_file($path)) return true; // missing file does not throw
    json_decode(file_get_contents($path), true);
    return json_last_error() === JSON_ERROR_NONE;
}

Try / catch

use Illuminate\Foundation\ViteException;

try {
    $fonts = app('vite.fonts')->manifest($path);
} catch (ViteException $e) {
    // regenerate manifest or skip font injection
}

Prevention

When it happens

Trigger: A font manifest path is configured and the file at that path exists but is not parseable JSON — truncated, hand-edited, BOM-prefixed, contains a PHP error mixed in, or was written by a process that errored midway.

Common situations: Vite font plugin output corrupted by a failed/aborted build. Manual edits to the manifest that broke syntax. A different file written to the expected path (e.g. an error page from a CDN). Version mismatch between the font plugin and the consuming code expecting a newer schema.

Related errors


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