{"record":{"id":"2232740e38ee4f5b","repo":"serbanghita/Mobile-Detect","slug":"is-tablet-err","errorCode":"IS_TABLET_ERR","errorMessage":"Cache problem in isTablet(): {$e->getMessage()}","messagePattern":"Cache problem in isTablet\\(\\): (.+?)","errorType":"exception","errorClass":"MobileDetectException","httpStatus":null,"severity":"error","filePath":"src/MobileDetect.php","lineNumber":1513,"sourceCode":"                //                        $result = $this->match($regexString, $this->getUserAgent());\n                //                        if ($result) {\n                //                            $this->cache->set($cacheKey, true, $this->config['cacheTtl']);\n                //                            return true;\n                //                        }\n                //                    }\n                //                } else {\n                //                    // assume the regex is a \"string\"\n                //                    if ($this->match($_regex, $this->getUserAgent())) {\n                //                        $this->cache->set($cacheKey, true, $this->config['cacheTtl']);\n                //                        return true;\n                //                    }\n                //                }\n            }\n\n            $this->cache->set($cacheKey, false, $this->config['cacheTtl']);\n            return false;\n        } catch (CacheInvalidArgumentException | CacheException | PsrInvalidArgumentException $e) {\n            throw new MobileDetectException(\"Cache problem in isTablet(): {$e->getMessage()}\", MobileDetectExceptionCode::IS_TABLET_ERR, $e);\n        }\n    }\n\n    /**\n     * Checks if a rule (e.g. isIphone, isIOS, etc.) matches its regex against the User-Agent.\n     *\n     * @param string $ruleName\n     * @return bool\n     * @throws MobileDetectException\n     */\n    public function is(string $ruleName): bool\n    {\n        if (!$this->hasUserAgent()) {\n            throw new MobileDetectException('No user-agent has been set.', MobileDetectExceptionCode::INVALID_USER_AGENT_ERR);\n        }\n\n        if ($this->isUserAgentEmpty()) {\n            return false;","sourceCodeStart":1495,"sourceCodeEnd":1531,"githubUrl":"https://github.com/serbanghita/Mobile-Detect/blob/6ab7b0404df1da8da2aa2c56634362842d9c2a23/src/MobileDetect.php#L1495-L1531","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n$layout = $detect->isTablet() ? 'tablet' : 'desktop';\n// Redis down -> MobileDetectException: Cache problem in isTablet(): ...\n\n// after\nuse Detection\\Exception\\MobileDetectException;\nuse Detection\\Exception\\MobileDetectExceptionCode;\n\ntry {\n    $layout = $detect->isTablet() ? 'tablet' : 'desktop';\n} catch (MobileDetectException $e) {\n    if ($e->getCode() === MobileDetectExceptionCode::IS_TABLET_ERR) {\n        $layout = 'desktop'; // cache degraded; log $e->getPrevious()\n    } else {\n        throw $e;\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Pre-flight the backend you plan to inject:\n$probeKey = sha1('probe');\ntry {\n    $cache->set($probeKey, true, 1);\n    $cache->get($probeKey);\n} catch (\\Throwable $e) {\n    $cache = new \\Detection\\Cache\\Cache(); // fall back to bundled in-memory cache\n}\n$detect = new MobileDetect();","typeGuard":"function isPsr16Backend(mixed $cache): bool\n{\n    return $cache instanceof \\Psr\\SimpleCache\\CacheInterface;\n}","tryCatchPattern":"catch (MobileDetectException $e) {\n    if ($e->getCode() === MobileDetectExceptionCode::IS_TABLET_ERR) {\n        $layout = 'desktop'; // cache degraded; keep serving\n        error_log('detect cache: ' . $e->getPrevious()?->getMessage());\n    } else {\n        throw $e;\n    }\n}","preventionTips":["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."],"tags":["cache","psr-16","tablet","wrapper-exception","php"],"backgroundTag":"cache-backend-error","analyzedSha":"6ab7b0404df1da8da2aa2c56634362842d9c2a23","analyzedAt":"2026-08-21T04:49:48.090Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}