{"record":{"id":"c676da8211456643","repo":"nostra13/Android-Universal-Image-Loader","slug":"key-null-value-null","errorCode":null,"errorMessage":"key == null || value == null","messagePattern":"key == null \\|\\| value == null","errorType":"validation","errorClass":"NullPointerException","httpStatus":null,"severity":"error","filePath":"library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/LruMemoryCache.java","lineNumber":58,"sourceCode":"\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) {\n\t\t\t\tsize -= sizeOf(key, previous);\n\t\t\t}\n\t\t}\n\n\t\ttrimToSize(maxSize);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Remove the eldest entries until the total of remaining entries is at or below the requested size.\n\t *\n\t * @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements.","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/nostra13/Android-Universal-Image-Loader/blob/ba33ec64d0daaa881d35852460e78c58d086bc18/library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/LruMemoryCache.java#L40-L76","documentation":"LruMemoryCache.put(String, Bitmap) throws NullPointerException when either the key or the value is null. The cache's size accounting (sizeOf on both the inserted and the replaced bitmap) requires non-null entries, and caching null would corrupt the LRU bookkeeping. In normal use keys are generated URIs and values are decoded bitmaps, so this indicates a caller bug.","triggerScenarios":"Calling memoryCache.put(uri, null) after a decode failure; put(null, bitmap) with an unset URI; custom post-processors or custom caches forwarding null bitmaps into put().","commonSituations":"Custom code that pre-warms the cache and passes a bitmap variable that decode returned null for on OOM-corrupted streams; adapter code where the model's image URL field is null/optional.","solutions":["Only put a pair after checking both: if (uri != null && bitmap != null) cache.put(...)","Handle decode failure upstream (onLoadingFailed) instead of writing a null placeholder","Use ImageLoader's own pipeline (displayImage/loadImage), which never invokes put with nulls"],"exampleFix":"// before\nBitmap decoded = BitmapFactory.decodeStream(is);\nImageLoader.getInstance().getMemoryCache().put(uri, decoded); // decoded == null -> NPE\n\n// after\nBitmap decoded = BitmapFactory.decodeStream(is);\nif (uri != null && decoded != null) {\n    ImageLoader.getInstance().getMemoryCache().put(uri, decoded);\n}","handlingStrategy":"type-guard","validationCode":"if (uri != null && bitmap != null && !bitmap.isRecycled()) {\n    ImageLoader.getInstance().getMemoryCache().put(uri, bitmap);\n}","typeGuard":"static boolean isCacheableEntry(String key, Bitmap value) {\n    return key != null && value != null && !value.isRecycled();\n}","tryCatchPattern":null,"preventionTips":["Check decode results for null before caching them","Do not pre-warm the cache from background decoders without null checks","Never recycle a bitmap that is still inside the cache"],"tags":["memory-cache","null-safety","api-misuse"],"backgroundTag":null,"analyzedSha":"ba33ec64d0daaa881d35852460e78c58d086bc18","analyzedAt":"2026-08-14T15:41:15.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}