{"record":{"id":"95fbdfd976d7086f","repo":"nostra13/Android-Universal-Image-Loader","slug":"key-null","errorCode":null,"errorMessage":"key == null","messagePattern":"key == null","errorType":"validation","errorClass":"NullPointerException","httpStatus":null,"severity":"error","filePath":"library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/LruMemoryCache.java","lineNumber":46,"sourceCode":"\tprivate int size;\n\n\t/** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */\n\tpublic LruMemoryCache(int maxSize) {\n\t\tif (maxSize <= 0) {\n\t\t\tthrow new IllegalArgumentException(\"maxSize <= 0\");\n\t\t}\n\t\tthis.maxSize = maxSize;\n\t\tthis.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);\n\t}\n\n\t/**\n\t * Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head\n\t * of the queue. This returns null if a Bitmap is not cached.\n\t */\n\t@Override\n\tpublic final Bitmap get(String key) {\n\t\tif (key == null) {\n\t\t\tthrow new NullPointerException(\"key == null\");\n\t\t}\n\n\t\tsynchronized (this) {\n\t\t\treturn map.get(key);\n\t\t}\n\t}\n\n\t/** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */\n\t@Override\n\tpublic final boolean put(String key, Bitmap value) {\n\t\tif (key == null || value == null) {\n\t\t\tthrow new NullPointerException(\"key == null || value == null\");\n\t\t}\n\n\t\tsynchronized (this) {\n\t\t\tsize += sizeOf(key, value);\n\t\t\tBitmap previous = map.put(key, value);\n\t\t\tif (previous != null) {","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/nostra13/Android-Universal-Image-Loader/blob/ba33ec64d0daaa881d35852460e78c58d086bc18/library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/LruMemoryCache.java#L28-L64","documentation":"LruMemoryCache.get(String) rejects a null key with NullPointerException because the underlying LinkedHashMap access-order bookkeeping requires a real key, and silently returning null would mask caller bugs. Keys in UIL are the (non-null) URI strings generated internally by MemoryCacheUtil, so a null key reaching this method means the caller bypassed the normal pipeline.","triggerScenarios":"Directly calling memoryCache.get(null) on the cache obtained from ImageLoader.getMemoryCache(); passing a null String uri into custom code that forwards it as a cache key; a custom MemoryCacheAware wrapper that forwards null after a failed key generation.","commonSituations":"Custom caches or instrumentation code calling getMemoryCache().get(uri) with a uri variable that is null because the intent extra / model field was absent; tests poking the cache directly.","solutions":["Null-check the key before calling get: if (uri != null) cache.get(uri)","Route image access through ImageLoader.displayImage/loadImage, which null-checks URIs upstream","Fix the source producing null URIs (missing intent extras, optional JSON fields)"],"exampleFix":"// before\nBitmap b = ImageLoader.getInstance().getMemoryCache().get(uri); // uri may be null\n\n// after\nBitmap b = uri != null ? ImageLoader.getInstance().getMemoryCache().get(uri) : null;\nif (b == null) ImageLoader.getInstance().displayImage(uri, imageView);","handlingStrategy":"type-guard","validationCode":"if (uri != null) {\n    Bitmap b = ImageLoader.getInstance().getMemoryCache().get(uri);\n}","typeGuard":"static boolean isCacheableKey(String key) {\n    return key != null && key.length() > 0;\n}","tryCatchPattern":null,"preventionTips":["Route loads through displayImage/loadImage instead of touching the memory cache directly","Treat URIs as @NonNull in your model layer","Filter null URIs out of lists before invalidation loops"],"tags":["memory-cache","null-safety","api-misuse"],"backgroundTag":null,"analyzedSha":"ba33ec64d0daaa881d35852460e78c58d086bc18","analyzedAt":"2026-08-14T15:41:15.893Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}