{"record":{"id":"1f8e861e0b701ce4","repo":"google/ExoPlayer","slug":"failed-to-load-bitmap","errorCode":null,"errorMessage":"Failed to load bitmap.","messagePattern":"Failed to load bitmap\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java","lineNumber":716,"sourceCode":"    outputPlayerView.setPlayer(outputPlayer);\n    outputPlayerView.setControllerAutoShow(false);\n    outputPlayer.setMediaItem(outputMediaItem);\n    outputPlayer.prepare();\n    this.outputPlayer = outputPlayer;\n\n    // Only support showing jpg images.\n    if (uri.toString().endsWith(\"jpg\")) {\n      inputPlayerView.setVisibility(View.GONE);\n      inputImageView.setVisibility(View.VISIBLE);\n      inputTextView.setText(getString(R.string.input_image));\n\n      BitmapLoader bitmapLoader = new DataSourceBitmapLoader(getApplicationContext());\n      ListenableFuture<Bitmap> future = bitmapLoader.loadBitmap(uri);\n      try {\n        Bitmap bitmap = future.get();\n        inputImageView.setImageBitmap(bitmap);\n      } catch (ExecutionException | InterruptedException e) {\n        throw new IllegalArgumentException(\"Failed to load bitmap.\", e);\n      }\n    } else {\n      inputPlayerView.setVisibility(View.VISIBLE);\n      inputImageView.setVisibility(View.GONE);\n      inputTextView.setText(getString(R.string.input_video_no_sound));\n\n      ExoPlayer inputPlayer = new ExoPlayer.Builder(/* context= */ this).build();\n      inputPlayerView.setPlayer(inputPlayer);\n      inputPlayerView.setControllerAutoShow(false);\n      inputPlayerView.setOnClickListener(this::onClickingPlayerView);\n      outputPlayerView.setOnClickListener(this::onClickingPlayerView);\n      inputPlayer.setMediaItem(inputMediaItem);\n      inputPlayer.prepare();\n      this.inputPlayer = inputPlayer;\n      inputPlayer.setVolume(0f);\n      inputPlayer.play();\n    }\n    outputPlayer.play();","sourceCodeStart":698,"sourceCodeEnd":734,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java#L698-L734","documentation":"IllegalArgumentException thrown in TransformerActivity's input preview path when DataSourceBitmapLoader.loadBitmap(uri) completes exceptionally; future.get() wraps the failure in an ExecutionException (or the wait is interrupted). The demo only supports jpg inputs, so any decode/IO failure of the image surfaces as this error.","triggerScenarios":"Input URI ends with 'jpg' but the bytes are not a decodable JPEG (corrupt file, renamed png, unsupported variant like CMYK jpeg); URI unreadable (content provider revoked, file moved); loadBitmap future fails with a BitmapDecoderException; thread interrupted while waiting.","commonSituations":"User picks a non-jpg image with a .jpg extension; SAF grant expired; large image OOM inside the decoder; HEIC disguised as jpg.","solutions":["Verify the URI is readable and the bytes are really JPEG before calling loadBitmap (check BitmapFactory.decodeBounds or the content resolver type)","Catch ExecutionException separately and unwrap its cause for a specific message instead of a generic crash","Restore the interrupted flag when catching InterruptedException so the thread state is preserved","Support a broader set of image types or filter the picker to image/jpeg only"],"exampleFix":"// before\ntry {\n  Bitmap bitmap = future.get();\n  inputImageView.setImageBitmap(bitmap);\n} catch (ExecutionException | InterruptedException e) {\n  throw new IllegalArgumentException(\"Failed to load bitmap.\", e);\n}\n\n// after: degrade gracefully instead of crashing\ntry {\n  inputImageView.setImageBitmap(future.get());\n} catch (ExecutionException e) {\n  Log.e(TAG, \"Failed to load bitmap\", e.getCause());\n  showToast(R.string.general_error); // keep the video preview path\n} catch (InterruptedException e) {\n  Thread.currentThread().interrupt();\n}","handlingStrategy":"try-catch","validationCode":"private boolean isDecodableJpg(Uri uri) {\n  try (InputStream in = getContentResolver().openInputStream(uri)) {\n    BitmapFactory.Options opts = new BitmapFactory.Options();\n    opts.inJustDecodeBounds = true;\n    BitmapFactory.decodeStream(in, null, opts);\n    return opts.outWidth > 0; // header parsed -> decodable\n  } catch (IOException | SecurityException e) {\n    return false;\n  }\n}","typeGuard":null,"tryCatchPattern":"ListenableFuture<Bitmap> future = bitmapLoader.loadBitmap(uri);\ntry {\n  inputImageView.setImageBitmap(future.get());\n} catch (ExecutionException e) {\n  Log.e(TAG, \"bitmap decode failed\", e.getCause()); // degrade, do not crash\n  inputImageView.setVisibility(View.GONE);\n} catch (InterruptedException e) {\n  Thread.currentThread().interrupt();\n}","preventionTips":["Restrict the picker to image/jpeg so non-JPEG data cannot reach this path","Treat future.get() as fallible: unwrap ExecutionException.getCause() for the real reason","Restore the interrupt status whenever you catch InterruptedException"],"tags":["android","bitmap","image-decode","demo"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}