symfony/symfony · error · Symfony\Component\Cache\Exception\BadMethodCallException
Cannot call "%s::withSubNamespace()": this class doesn't imp
Error message
Cannot call "%s::withSubNamespace()": this class doesn't implement "%s".
What it means
TraceableAdapter wraps a cache pool to collect call statistics for profiling. The withSubNamespace() method delegates to the wrapped pool's withSubNamespace(), but only pools that implement Symfony\Contracts\Cache\NamespacedPoolInterface support sub-namespacing. If the wrapped adapter does not implement that interface (e.g. a plain PSR-6 pool or NullAdapter), this exception is thrown because there is no namespace-scoping capability to delegate to.
Source
Thrown at src/Symfony/Component/Cache/Adapter/TraceableAdapter.php:279
}
public function clearCalls(): void
{
$this->calls = [];
}
public function getPool(): AdapterInterface
{
return $this->pool;
}
/**
* @throws BadMethodCallException When the item pool is not a NamespacedPoolInterface
*/
public function withSubNamespace(string $namespace): static
{
if (!$this->pool instanceof NamespacedPoolInterface) {
throw new BadMethodCallException(\sprintf('Cannot call "%s::withSubNamespace()": this class doesn\'t implement "%s".', get_debug_type($this->pool), NamespacedPoolInterface::class));
}
$calls = &$this->calls; // ensures clones share the same array
$clone = clone $this;
$clone->namespace .= CacheItem::validateKey($namespace).':';
$clone->pool = $this->pool->withSubNamespace($namespace);
return $clone;
}
protected function start(string $name): TraceableAdapterEvent
{
$this->calls[] = $event = new TraceableAdapterEvent();
$event->name = $name;
$event->start = microtime(true);
$event->namespace = $this->namespace;
return $event;View on GitHub (pinned to 698e28026c)
Solutions
- Verify the wrapped adapter implements NamespacedPoolInterface before calling withSubNamespace().
- Use a built-in adapter that supports namespacing (RedisAdapter, PdoAdapter, FilesystemAdapter, etc.) instead of a bare PSR-6 pool.
- Call withSubNamespace() on the underlying pool directly rather than through TraceableAdapter if the pool supports it but the tracer was constructed over an incompatible pool.
Example fix
// before
$traced = new TraceableAdapter($someThirdPartyPsr6Pool);
$sub = $traced->withSubNamespace('users'); // throws
// after
use Symfony\Contracts\Cache\NamespacedPoolInterface;
if ($traced->getPool() instanceof NamespacedPoolInterface) {
$sub = $traced->withSubNamespace('users');
} else {
// fallback: prefix keys manually
$key = 'users.' . $key;
} Defensive patterns
Strategy: type-guard
Validate before calling
use Symfony\Contracts\Cache\NamespacedPoolInterface;
if ($traced->getPool() instanceof NamespacedPoolInterface) {
$sub = $traced->withSubNamespace('prefix');
} else {
// prefix keys manually or choose a compatible adapter
} Type guard
function poolSupportsNamespacing(\Symfony\Component\Cache\Adapter\TraceableAdapter $ta): bool {
return $ta->getPool() instanceof \Symfony\Contracts\Cache\NamespacedPoolInterface;
} Try / catch
try {
$sub = $traced->withSubNamespace('ns');
} catch (\Symfony\Component\Cache\Exception\BadMethodCallException $e) {
// fall back to manual key prefixing
$key = 'ns_' . $key;
} Prevention
- Always check instanceof NamespacedPoolInterface before calling withSubNamespace().
- Prefer built-in Symfony adapters that implement NamespacedPoolInterface.
- Document which adapters your tracing layer supports.
When it happens
Trigger: Calling $traceableAdapter->withSubNamespace('foo') when the wrapped pool (passed to the TraceableAdapter constructor) is an adapter that does not implement NamespacedPoolInterface — for example a third-party PSR-6 pool, NullAdapter, or ArrayAdapter in certain configurations.
Common situations: Developers wire a custom or third-party PSR-6 CacheItemPoolInterface into the cache profiler/collector (web debug toolbar) and then attempt to namespace-scoped access. Also occurs in test environments where a simple mock pool is wrapped by TraceableAdapter and namespace operations are attempted.
Related errors
- Expiration date must be an integer, a DateInterval or null,
- Cache tag must be string or object that implements __toStrin
- Cache key must be string, "%s" given.
- The class "%s" does not implement the "%s" interface.
- Cache item "%s" comes from a non tag-aware pool: you cannot
AI-assisted analysis of symfony/symfony@698e28026c (2026-08-06).
Data as JSON: /api/errors/2f103665ba1dc8cb.
Report an issue: GitHub.