{"record":{"id":"e7eb807823d0085d","repo":"serbanghita/Mobile-Detect","slug":"is-magic-err","errorCode":"IS_MAGIC_ERR","errorMessage":"Cache problem in is(): {$e->getMessage()}","messagePattern":"Cache problem in is\\(\\): (.+?)","errorType":"exception","errorClass":"MobileDetectException","httpStatus":null,"severity":"error","filePath":"src/MobileDetect.php","lineNumber":1548,"sourceCode":"        if ($this->isUserAgentEmpty()) {\n            return false;\n        }\n\n        // Cache check.\n        try {\n            $cacheKey = $this->createCacheKey($ruleName);\n            $cacheItem = $this->cache->get($cacheKey);\n            if ($cacheItem !== null) {\n                return $cacheItem;\n            }\n\n            $result = $this->matchUserAgentWithRule($ruleName);\n\n            // Cache save.\n            $this->cache->set($cacheKey, $result, $this->config['cacheTtl']);\n            return $result;\n        } catch (CacheInvalidArgumentException | CacheException | PsrInvalidArgumentException $e) {\n            throw new MobileDetectException(\"Cache problem in is(): {$e->getMessage()}\", MobileDetectExceptionCode::IS_MAGIC_ERR, $e);\n        }\n    }\n\n    /**\n     * Some detection rules are relative (not standard),\n     * because of the diversity of devices, vendors and\n     * their conventions in representing the User-Agent or\n     * the HTTP headers.\n     *\n     * This method will be used to check custom regexes against\n     * the User-Agent string.\n     *\n     * @param string $regex\n     * @param string $userAgent\n     * @return bool\n     *\n     * @todo: search in the HTTP headers too.\n     */","sourceCodeStart":1530,"sourceCodeEnd":1566,"githubUrl":"https://github.com/serbanghita/Mobile-Detect/blob/6ab7b0404df1da8da2aa2c56634362842d9c2a23/src/MobileDetect.php#L1530-L1566","documentation":"is() (src/MobileDetect.php:1548) re-throws any CacheException, CacheInvalidArgumentException, or Psr\\SimpleCache\\InvalidArgumentException raised during its cache get/set or during createCacheKey() as MobileDetectException with code IS_MAGIC_ERR (0x4), chaining the cause. Because every magic isXXXX() call routes through __call -> is(), this is the wrapper you hit when cache trouble occurs inside a magic detection call (e.g. isIphone(), isBot()).","triggerScenarios":"$detect->isIphone() with 'cacheKeyFn' misconfigured (non-callable, or producing keys that fail checkKey) — the inner CacheException/CacheInvalidArgumentException originates in createCacheKey() or the Cache; a custom PSR-16 backend injected instead of the bundled Cache throwing on get/set (Redis down, strict key validation, unserializable values).","commonSituations":"Surfaces only after replacing the default in-memory cache with a real backend (default Cache + sha1 keys always pass validation); production-only cache outages; DI misconfiguration after a framework upgrade; per-user UA-flag caching with keys built outside MobileDetect.","solutions":["Drill into the cause: $e->getPrevious() — 'cacheKeyFn is not a function.' means a config problem; 'Invalid key: ...' means the key fn output violates the charset rule.","Restore a callable hash for 'cacheKeyFn' ('sha1' default, 'md5', or a hash() closure).","Audit the custom CacheInterface implementation's exact get/set signatures and failure modes; have backend outages return defaults or log rather than throw when detection is non-critical.","Catch narrowly by code (IS_MAGIC_ERR) so genuine detection bugs aren't swallowed."],"exampleFix":"// before\nif ($detect->isBot()) { /* ... */ } // Redis down -> IS_MAGIC_ERR wrapper\n\n// after\nuse Detection\\Exception\\MobileDetectException;\nuse Detection\\Exception\\MobileDetectExceptionCode;\n\ntry {\n    $bot = $detect->isBot();\n} catch (MobileDetectException $e) {\n    if ($e->getCode() !== MobileDetectExceptionCode::IS_MAGIC_ERR) {\n        throw $e;\n    }\n    $bot = false; // cache degraded; log $e->getPrevious()->getMessage()\n}","handlingStrategy":"try-catch","validationCode":"// Guard the two root causes before any magic call:\n$config = ['cacheKeyFn' => 'sha1'];\nassert(is_callable($config['cacheKeyFn']));\n// and prove the backend round-trips one MobileDetect-shaped key:\n$cache->set(str_repeat('a', 40), true, 1);","typeGuard":"// The bundled default never fails; guard only swapped-in backends:\nfunction backendAcceptsDetectorKeys(\\Psr\\SimpleCache\\CacheInterface $c): bool\n{\n    try {\n        return $c->set(str_repeat('a', 40), 1, 1);\n    } catch (\\Throwable) {\n        return false;\n    }\n}","tryCatchPattern":"catch (MobileDetectException $e) {\n    if ($e->getCode() === MobileDetectExceptionCode::IS_MAGIC_ERR) {\n        // is()/isXXXX() cache path failed; retry cache-less\n        $fresh = new \\Detection\\MobileDetect();\n        $fresh->setUserAgent($ua);\n        $result = $fresh->is($rule);\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Remember every isXXXX() funnels through is() — one bad cache config breaks all magic calls at once.","Validate cacheKeyFn output shape in a boot-time smoke test, not in the request path.","Distinguish by code: IS_MAGIC_ERR (0x4) means cache trouble, not a bad rule name."],"tags":["cache","psr-16","magic-methods","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"}