laravel/framework · error · BadMethodCallException

This cache store does not support locks.

Error message

This cache store does not support locks.

What it means

Thrown by Cache\Repository::funnel() when the configured cache store does not implement Illuminate\Contracts\Cache\LockProvider. Atomic locks (Cache::lock, block, funnel, throttle) require lock support that file/array/DynamoDB stores do not provide.

Source

Thrown at src/Illuminate/Cache/Repository.php:742

     * @return TReturn
     *
     * @throws \Illuminate\Contracts\Cache\LockTimeoutException
     */
    public function withoutOverlapping($key, callable $callback, $lockFor = 0, $waitFor = 10, $owner = null)
    {
        return $this->store->lock(enum_value($key), $lockFor, $owner)->block($waitFor, $callback);
    }

    /**
     * Funnel a callback for a maximum number of simultaneous executions.
     *
     * @param  \UnitEnum|string  $name
     * @return \Illuminate\Cache\Limiters\ConcurrencyLimiterBuilder
     */
    public function funnel($name)
    {
        if (! $this->store instanceof LockProvider) {
            throw new BadMethodCallException('This cache store does not support locks.');
        }

        return new ConcurrencyLimiterBuilder($this, enum_value($name));
    }

    /**
     * Remove an item from the cache.
     *
     * @param  \UnitEnum|array|string  $key
     * @return bool
     */
    public function forget($key)
    {
        $key = enum_value($key);

        $this->event(new ForgettingKey($this->getName(), $key));

        return tap($this->store->forget($this->itemKey($key)), function ($result) use ($key) {

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Switch CACHE_STORE to redis, database, memcached, or dynamodb (all implement LockProvider).
  2. Guard the call: if (Cache::getStore() instanceof \Illuminate\Contracts\Cache\LockProvider) { ... }.
  3. In phpunit set CACHE_STORE=array only for tests that don't exercise locks, and use a dedicated redis connection for lock tests.
  4. Refactor away from locks (e.g., use a DB unique constraint or a job middleware) if no lock-capable store is available.

Example fix

// before
Cache::lock('process:'.$id, 60)->block(5, fn () => doWork());

// after  (env)
// .env: CACHE_STORE=redis
// or guard at runtime
if (Cache::getStore() instanceof \Illuminate\Contracts\Cache\LockProvider) {
    Cache::lock('process:'.$id, 60)->block(5, fn () => doWork());
} else {
    doWork();
}
Defensive patterns

Strategy: validation

Validate before calling

if (! (Cache::getStore() instanceof \Illuminate\Contracts\Cache\LockProvider)) {
    // locks unavailable; choose a fallback path
}

Type guard

function cacheSupportsLocks(): bool {
    return Cache::getStore() instanceof \Illuminate\Contracts\Cache\LockProvider;
}

Try / catch

try {
    Cache::lock('job:'.$id, 60)->block(5, fn () => doWork());
} catch (\BadMethodCallException $e) {
    // store lacks lock support; run without a lock or fail loudly
    doWork();
}

Prevention

When it happens

Trigger: Calling Cache::funnel('name'), Cache::lock('key'), or Cache::block('key', $cb) while CACHE_DRIVER/STORE is file, array, or another non-LockProvider store.

Common situations: Local dev with CACHE_STORE=file (or array in tests) hitting a Cache::lock()/->block() call that works in prod with redis/database; running queue/job code that uses Cache::lock in the testing environment.

Related errors


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