laravel/framework · error · LogicException

Your configuration files could not be serialized because the

Error message

Your configuration files could not be serialized because the value at "{$key}" is non-serializable.

What it means

Thrown by ConfigCacheCommand::handle() during config:cache when the cached config file, written via var_export(), cannot be required() back (PHP throws on load). The command then iterates every dotted config key, evals its var_export representation, and reports the FIRST key whose value fails to round-trip — pinpointing the non-serializable config value (e.g., a Closure, a resource, an object without serializable form).

Source

Thrown at src/Illuminate/Foundation/Console/ConfigCacheCommand.php:77

        $config = $this->getFreshConfiguration();

        $configPath = $this->laravel->getCachedConfigPath();

        $this->files->put(
            $configPath, '<?php return '.var_export($config, true).';'.PHP_EOL
        );

        try {
            require $configPath;
        } catch (Throwable $e) {
            $this->files->delete($configPath);

            foreach (Arr::dot($config) as $key => $value) {
                try {
                    eval(var_export($value, true).';');
                } catch (Throwable $e) {
                    throw new LogicException("Your configuration files could not be serialized because the value at \"{$key}\" is non-serializable.", 0, $e);
                }
            }

            throw new LogicException('Your configuration files are not serializable.', 0, $e);
        }

        $this->components->info('Configuration cached successfully.');
    }

    /**
     * Boot a fresh copy of the application configuration.
     *
     * @return array
     */
    protected function getFreshConfiguration()
    {
        $app = require $this->laravel->bootstrapPath('app.php');

View on GitHub (pinned to deac04fbdc)

Solutions

  1. Inspect the config key named in the message and replace the non-serializable value (Closure/resource/object) with a plain scalar/array.
  2. Move Closure-based logic into service providers or boot logic instead of config files.
  3. Run config:cache only in environments where all config values are serializable.
  4. After fixing, re-run php artisan config:cache.

Example fix

// before - Closure in config (config/services.php)
'feature' => fn () => app('settings')->all(),

// after - plain serializable value or move to a provider
'feature' => ['enabled' => env('FEATURE_ENABLED', false)],
Defensive patterns

Strategy: validation

Validate before calling

// Scan config for non-serializable values before caching
foreach (Arr::dot(app('config')->all()) as $key => $value) {
    @eval(var_export($value, true).';');
    if (error_get_last()) {
        throw new LogicException('Non-serializable config at '.$key);
    }
}

Type guard

function isSerializableConfig(mixed $value): bool {
    try {
        eval(var_export($value, true).';');
        return true;
    } catch (\Throwable) {
        return false;
    }
}

Try / catch

// config:cache is a CLI command; guard in CI:
try {
    \Illuminate\Support\Facades\Artisan::call('config:cache');
} catch (\LogicException $e) {
    if (str_contains($e->getMessage(), 'non-serializable')) {
        // fix the named config key, then retry
    }
}

Prevention

When it happens

Trigger: Running php artisan config:cache when a config value cannot survive var_export + require. This happens when a config value is a Closure (common for services.file_DRIVER or dynamic configs), a resource, or an anonymous/object instance that var_export can't represent.

Common situations: Storing a Closure in config (e.g., 'redis' => fn() => ... outside allowed closures), or an object/resource; the message names the exact dotted key (e.g., 'database.connections.mysql.something') at fault.

Related errors


AI-assisted analysis of laravel/framework@deac04fbdc (2026-08-06). Data as JSON: /api/errors/3bb22ed8c1c1ce45. Report an issue: GitHub.