[Android] Image drops `source.headers` for a single-object source since 0.86 (only array sources forward headers)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 75/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- android, javascript, react-native
- Domain
- mobile-dev
Research direction
The bug is in Libraries/Image/Image.android.js. Start by reading the render function around line 300. The fix is to destructure headers from the single-object source and assign them to nativeProps.headers, mirroring the array-source branch. Test by building a minimal React Native app on Android that loads an authenticated image, or run existing Image tests to ensure the change works.
Written by the indexing model from the issue text.
Description
Description
Since React Native 0.86, <Image source={{uri, headers}} /> on Android no longer sends the headers with the image request when source is a single object. The headers are still forwarded when source is an array of sources.
Cause (Libraries/Image/Image.android.js, 0.86.3): in the render function the native headers prop is only set inside the if (Array.isArray(source_)) branch:
if (Array.isArray(source_)) {
const {headers: sourceHeaders, width: sourceWidth, height: sourceHeight} = source_[0];
if (sourceHeaders != null) {
nativeProps.headers = sourceHeaders;
}
…
} else {
const {uri, width: sourceWidth, height: sourceHeight} = source_; // headers are dropped here
…
nativeProps.source = [source_];
}
The Android native view (ReactImageView) takes request headers only from the separate headers prop (ReactImageManager.setHeaders → ReactNetworkImageRequest.fromBuilderWithHeaders), not from the per-source entries, so the request is made without them. In 0.79 the prop was built as headers: source?.[0]?.headers || source?.headers, which covered both forms. iOS is not affected (headers are read from the source natively).
Real-world impact: every authenticated image (e.g. headers: {Authorization: 'Bearer …'}) silently fails with HTTP 401 on Android after upgrading to 0.86; onError reports Unexpected HTTP code Response{protocol=h2, code=401, …}.
Steps to reproduce
- Render an image whose server requires a request header, single-object source:
<Image source={{uri: 'https://example.com/protected.png', headers: {Authorization: 'Bearer <token>'}}} style={{width: 96, height: 96}} onError={e => console.log(e.nativeEvent.error)} /> - On Android 0.86.x the request is sent without
Authorization(server answers 401,onErrorfires, the image never loads). - The same element with an array source works:
source={[{uri: '…', headers: {…}}]}. - On 0.79.x (and on iOS) both forms send the header.
React Native Version
0.86.3
Affected Platforms
Runtime - Android
Output of npx @react-native-community/cli info
System:
OS: macOS 26.6.2
CPU: (10) arm64 Apple M4
Memory: 2.56 GB / 16.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 24.16.0
path: /opt/homebrew/opt/node@24/bin/node
Yarn:
version: 4.16.0
path: /opt/homebrew/opt/node@24/bin/yarn
npm:
version: 11.13.0
path: /opt/homebrew/opt/node@24/bin/npm
Watchman:
version: 2026.06.01.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.16.2
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 27.0
- iOS 27.0
- macOS 27.0
- tvOS 27.0
- visionOS 27.0
- watchOS 27.0
Android SDK:
API Levels:
- "34"
- "35"
- "36"
- "36"
Build Tools:
- 34.0.0
- 35.0.0
- 36.0.0
- 36.1.0
- 37.0.0
System Images:
- android-36 | Google APIs ARM 64 v8a
Android NDK: Not Found
IDEs:
Android Studio: 2026.1 AI-261.23567.138.2611.15503007
Xcode:
version: 27.0/27A266a
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.19
path: /usr/bin/javac
Ruby:
version: 4.0.5
path: /opt/homebrew/opt/ruby/bin/ruby
Stacktrace or Logs
[Image onError] Unexpected HTTP code Response{protocol=h2, code=401, message=, url=https://…/image?v=…}
(Replaying the exact URL with the same Authorization header via curl returns 200; the header simply is not attached by the Android image request.)
MANDATORY Reproducer
Minimal snippet above; the defect is a one-line omission in Libraries/Image/Image.android.js. Proposed fix (we run it as a patch-package patch on 0.86.3):
} else {
- const {uri, width: sourceWidth, height: sourceHeight} = source_;
+ const {
+ uri,
+ headers: sourceHeaders,
+ width: sourceWidth,
+ height: sourceHeight,
+ } = source_;
if (uri === '') {
console.warn('source.uri should not be an empty string');
}
+ if (sourceHeaders != null) {
+ nativeProps.headers = sourceHeaders;
+ }
A harness that transpiles Image.android.js with @react-native/babel-preset, renders it with a mocked native component and asserts the headers prop for object and array sources fails on 0.86.3 and passes with the change; happy to open a PR with it if that helps.
Screenshots and Videos
Not needed: the image never loads (401), onError fires.
- Dominant language
- C++
- Stars
- 127k
- Forks
- 25.3k
- PR merge metrics
- No merged PRs in 30d
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from react/react-native
-
Linking.getInitialURL() returns the task's first link after a link relaunches a reclaimed Android appPossibly taken @YevheniiKotyrlo claimed this 2 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
react/react-native#59006 · 2 comments ·
Maintainers usually reply within 1 day
-
Fabric TextInput: prepareForRecycle leaves stale inputAccessoryViewButtonLabel (empty Done bar)Possibly taken @jkasprzyk17 claimed this 1 day ago. OpenNeeds: Author Feedback Needs: Repro
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
react/react-native#58952 · 1 comment ·
Maintainers usually reply within 1 day
-
Needs: Attention Needs: Repro
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
react/react-native#58904 · 2 comments ·
Maintainers usually reply within 1 day
-
Needs: Author Feedback Needs: Repro
Difficulty 1/5 Under an hour Newbie friendliness 92/100
react/react-native#58621 · 1 comment ·
Maintainers usually reply within 1 day
-
Add TypeScript declaration for the performance globalPossibly taken @Cedric921 claimed this 11 days ago. OpenNeeds: Attention Needs: Repro
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
react/react-native#58610 · 5 comments ·
Maintainers usually reply within 1 day
All issues in react/react-native
Similar issues
-
agent:Windows bug code-review LOW testing
Difficulty 2/5 1-3 hours Newbie friendliness 63/100
Maintainers usually reply within 1 day
-
[Cleanup] Include the public header in work_split.cppPossibly taken @blozano-tt claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
tenstorrent/tt-metal#60850 ·
Maintainers usually reply within 1 day
-
Build: the CUDA backend fails without cuDNN instead of skipping the cuDNN shim (as the cuDF shim does)Possibly taken A pull request linked to this issue is open or already merged. Open
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
beehive-lab/TornadoVM#1248 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SimVascular/svZeroDSolver#253 ·
-
bug Filter
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
BlueQuartzSoftware/simplnx#1825 ·
Maintainers usually reply within 3 days