serbanghita/Mobile-Detect · error · MobileDetectException
IS_TABLET_ERR
IS_TABLET_ERR
Error message
Cache problem in isTablet(): {$e->getMessage()} What it means
isTablet() wraps its cache read/write in a try/catch and re-throws CacheException, CacheInvalidArgumentException, or a PSR InvalidArgumentException as MobileDetectException with code IS_TABLET_ERR (0x3), chaining the cause. The bundled in-memory Cache with the default 'sha1' cacheKeyFn cannot trigger it, so in practice a custom PSR-16 backend injected into MobileDetect threw, or createCacheKey() failed on a misconfigured cacheKeyFn. The IS_TABLET_ERR code plus the 'Cache problem in isTablet():' prefix tell you the detection logic itself is fine — the storage layer failed.
Source
Thrown at src/MobileDetect.php:1513
// $result = $this->match($regexString, $this->getUserAgent());
// if ($result) {
// $this->cache->set($cacheKey, true, $this->config['cacheTtl']);
// return true;
// }
// }
// } else {
// // assume the regex is a "string"
// if ($this->match($_regex, $this->getUserAgent())) {
// $this->cache->set($cacheKey, true, $this->config['cacheTtl']);
// return true;
// }
// }
}
$this->cache->set($cacheKey, false, $this->config['cacheTtl']);
return false;
} catch (CacheInvalidArgumentException | CacheException | PsrInvalidArgumentException $e) {
throw new MobileDetectException("Cache problem in isTablet(): {$e->getMessage()}", MobileDetectExceptionCode::IS_TABLET_ERR, $e);
}
}
/**
* Checks if a rule (e.g. isIphone, isIOS, etc.) matches its regex against the User-Agent.
*
* @param string $ruleName
* @return bool
* @throws MobileDetectException
*/
public function is(string $ruleName): bool
{
if (!$this->hasUserAgent()) {
throw new MobileDetectException('No user-agent has been set.', MobileDetectExceptionCode::INVALID_USER_AGENT_ERR);
}
if ($this->isUserAgentEmpty()) {
return false;View on GitHub (pinned to 6ab7b0404d)
Solutions
- Read $e->getPrevious() to find the underlying cache exception and fix the backend issue (connectivity, serializer, key rules).
- Ensure cacheKeyFn output is always a valid key: keep 'sha1' or use fn(string $k): string => hash('sha256', $k).
- Make the custom backend PSR-16-conformant: throw InvalidArgumentException only for invalid arguments, not for backend outages.
- Catch MobileDetectException narrowly, match IS_TABLET_ERR, and fall back to a default layout while logging the previous exception.
Example fix
// before
$layout = $detect->isTablet() ? 'tablet' : 'desktop';
// Redis down -> MobileDetectException: Cache problem in isTablet(): ...
// after
use Detection\Exception\MobileDetectException;
use Detection\Exception\MobileDetectExceptionCode;
try {
$layout = $detect->isTablet() ? 'tablet' : 'desktop';
} catch (MobileDetectException $e) {
if ($e->getCode() === MobileDetectExceptionCode::IS_TABLET_ERR) {
$layout = 'desktop'; // cache degraded; log $e->getPrevious()
} else {
throw $e;
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight the backend you plan to inject:
$probeKey = sha1('probe');
try {
$cache->set($probeKey, true, 1);
$cache->get($probeKey);
} catch (\Throwable $e) {
$cache = new \Detection\Cache\Cache(); // fall back to bundled in-memory cache
}
$detect = new MobileDetect(); Type guard
function isPsr16Backend(mixed $cache): bool
{
return $cache instanceof \Psr\SimpleCache\CacheInterface;
} Try / catch
catch (MobileDetectException $e) {
if ($e->getCode() === MobileDetectExceptionCode::IS_TABLET_ERR) {
$layout = 'desktop'; // cache degraded; keep serving
error_log('detect cache: ' . $e->getPrevious()?->getMessage());
} else {
throw $e;
}
} Prevention
- Check $e->getPrevious() first — the real failure is one layer down in the cache backend.
- Custom backends should throw PSR InvalidArgumentException only for bad arguments, never for connectivity loss.
- Alert on cache-degraded fallbacks so silent degradation doesn't persist unnoticed.
When it happens
Trigger: A Redis/APCu/filesystem PSR-16 adapter throwing inside get()/set() (connection down, serialization failure, its own key policy rejecting the key); 'cacheKeyFn' set to a non-callable or to a function returning keys violating the bundled charset rule; a DI container wiring a PSR-6 (not PSR-16) cache whose signatures don't match.
Common situations: Production-only backend failures that never show in dev because dev uses the default in-memory cache; swapping in a project-wide shared cache for cross-worker deduplication; Symfony/cache adapters with stricter key rules (spaces, braces, reserved characters) when cacheKeyFn was also customized.
Related errors
- IS_MOBILE_ERR
- IS_MAGIC_ERR
- Cache key must be a string.
- Invalid key: '$key'. Must be alphanumeric, can contain _ and
- TTL must be null, int, or DateInterval.
AI-assisted analysis of serbanghita/Mobile-Detect@6ab7b0404d (2026-08-21).
Data as JSON: /api/errors/2232740e38ee4f5b.
Report an issue: GitHub.