{"record":{"id":"12a4378bec562be8","repo":"NativeScript/NativeScript","slug":"cache-is-closed","errorCode":null,"errorMessage":"cache is closed","messagePattern":"cache is closed","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"packages/ui-mobile-base/android/widgets/src/main/java/org/nativescript/widgets/image/DiskLruCache.java","lineNumber":672,"sourceCode":"\t\tlruEntries.remove(key);\n\n\t\tif (journalRebuildRequired()) {\n\t\t\texecutorService.submit(cleanupCallable);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns true if this cache has been closed.\n\t */\n\tpublic boolean isClosed() {\n\t\treturn journalWriter == null;\n\t}\n\n\tprivate void checkNotClosed() {\n\t\tif (journalWriter == null) {\n\t\t\tthrow new IllegalStateException(\"cache is closed\");\n\t\t}\n\t}\n\n\t/**\n\t * Force buffered operations to the filesystem.\n\t */\n\tpublic synchronized void flush() throws IOException {\n\t\tcheckNotClosed();\n\t\ttrimToSize();\n\t\tjournalWriter.flush();\n\t}\n\n\t/**\n\t * Closes this cache. Stored values will remain on the filesystem.\n\t */\n\tpublic synchronized void close() throws IOException {\n\t\tif (journalWriter == null) {\n\t\t\treturn; // already closed","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/NativeScript/NativeScript/blob/6800aefa6511d23ddad8beb38ccc8541c5e91628/packages/ui-mobile-base/android/widgets/src/main/java/org/nativescript/widgets/image/DiskLruCache.java#L654-L690","documentation":"DiskLruCache operations (get, edit, remove, flush) call checkNotClosed(), which throws IllegalStateException if the cache was already closed (journalWriter == null). Once close() runs, the cache cannot be used again — create a new instance instead.","triggerScenarios":"Calling get/edit/remove/flush on a DiskLruCache instance after close() has been called, typically from a stale singleton reference or a background thread racing with close()/delete().","commonSituations":"Activity/fragment lifecycle closing the image cache while a background load still uses it; calling delete() (which closes) then continuing to use the old reference; double-close followed by use.","solutions":["Keep a single cache owner that closes the cache only when all consumers are done; null out references after close().","Guard calls with cache.isClosed() before use, or recreate via DiskLruCache.open(...) when closed.","Synchronize close() and cache accesses on the same lock to avoid racing threads.","Catch IllegalStateException and reopen the cache."],"exampleFix":"// before\nimageCache.close();\nimageCache.get(key); // throws \"cache is closed\"\n// after\nif (imageCache.isClosed()) {\n  imageCache = DiskLruCache.open(dir, 1, 1, maxSize);\n}\nimageCache.get(key);","handlingStrategy":"validation","validationCode":"if (cache.isClosed()) {\n  cache = DiskLruCache.open(cacheDir, 1, 1, maxSize);\n}","typeGuard":null,"tryCatchPattern":"try {\n  return cache.get(key);\n} catch (IllegalStateException closed) {\n  cache = DiskLruCache.open(cacheDir, 1, 1, maxSize);\n  return cache.get(key);\n}","preventionTips":["Only close the cache when no background tasks can use it","Null/recreate references after close()","Synchronize close() and cache ops on one lock"],"tags":["android","disk-cache","lifecycle"],"backgroundTag":"cache-closed-use-after-close","analyzedSha":"6800aefa6511d23ddad8beb38ccc8541c5e91628","analyzedAt":"2026-08-30T20:04:56.809Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}