Skip to content

fix(resource-fetcher): avoid this in static fs field initializer - #1310

Merged
msluszniak merged 1 commit into
software-mansion:mainfrom
danchily2:fix/resource-fetcher-static-this
Jul 17, 2026
Merged

fix(resource-fetcher): avoid this in static fs field initializer#1310
msluszniak merged 1 commit into
software-mansion:mainfrom
danchily2:fix/resource-fetcher-static-this

Conversation

@danchily2

@danchily2 danchily2 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Description

ResourceFetcher.fs.readAsString is an async arrow inside a static class-field initializer and relies on this binding to the class. Because the package resolves through the "react-native": "src/index" entry, Metro compiles this TypeScript source with the consuming app's Babel config. Under @react-native/babel-preset with unstable_transformProfile: 'hermes-stable' (or 'hermes-canary'), the async transform hoists the arrow's this capture to module scope:

var _this = this; // module scope!
class ResourceFetcher {
  static fs = { readAsString: /* ... */ _this.getAdapter().readAsString(path) /* ... */ };
}

_this.getAdapter is undefined, so every model load fails with TypeError: undefined is not a function inside LLMController.load, right after the download finishes — on both iOS and Android. The default transform profile compiles it correctly, which is why this only bites apps that opt into the hermes profiles.

Fix: reference the class by name instead of this. One line, no behavior change.

Introduces a breaking change?

  • Yes
  • No

Type of change

  • Bug fix (change which fixes an issue)
  • New feature (change which adds functionality)
  • Documentation update (improves or adds clarity to existing documentation)
  • Other (chores, tests, code style improvements etc.)

Tested on

  • iOS
  • Android

Testing instructions

  1. In a bare RN app (RN 0.86, New Architecture) set unstable_transformProfile: 'hermes-stable' on @react-native/babel-preset in babel.config.js.
  2. Load any LLM, e.g. useLLM({ model: GEMMA4_E2B }), on a physical device.
  3. Without this patch: load fails with TypeError: undefined is not a function after the download completes. With it: the model loads and generates.

Reproducible without a device: run @babel/core on src/utils/ResourceFetcher.ts with the preset above and inspect the output — the var _this = this hoist lands at module scope.

Verified end-to-end on a physical iPhone 16 with GEMMA4_E2B (MLX backend): download → load → generation all work with this patch (applied via yarn patch against 0.9.2).

Screenshots

N/A

Related issues

N/A

Checklist

  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have updated the documentation accordingly
  • My changes generate no new warnings

Additional notes

A repo-wide sweep found no other this usage inside static-field initializers, so this is the only affected site.

🤖 Generated with Claude Code

An async arrow inside the static 'fs' class-field initializer relies on
'this' binding to the class. When an app resolves the library through the
"react-native": "src/index" entry, Metro compiles this TS source with the
app's Babel config; under @react-native/babel-preset with
unstable_transformProfile 'hermes-stable' or 'hermes-canary', the async
transform hoists the arrow's 'this' capture (var _this = this) to module
scope. ResourceFetcher.fs.readAsString then calls _this.getAdapter() on the
module context and every LLM/model load fails with
'TypeError: undefined is not a function' right after download.

Referencing the class by name sidesteps the transform entirely.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@msluszniak msluszniak added the bug fix PRs that are fixing bugs label Jul 16, 2026
@msluszniak

Copy link
Copy Markdown
Member

Thank you for the PR, tested and works correctly

@msluszniak
msluszniak merged commit a0bf85b into software-mansion:main Jul 17, 2026
24 checks passed
@msluszniak msluszniak mentioned this pull request Jul 28, 2026
7 tasks
msluszniak added a commit that referenced this pull request Aug 3, 2026
## Description

Patch release **v0.9.3**. The bundleId/system telemetry change (#1311)
is already merged into `release/0.9`. This PR cherry-picks the following
bug fixes from `main` (chronological order, with `-x`) and bumps the
core package version:

- fix(resource-fetcher): avoid `this` in static `fs` field initializer
(#1310)
- fix(android): forward ExecuTorch consumer ProGuard rules (#1325)

Bump `packages/react-native-executorch/package.json` to `0.9.3`. Adapter
packages (`bare-resource-fetcher`, `expo-resource-fetcher`) untouched by
the cherry-picks — versions not bumped.

### Introduces a breaking change?

- [ ] Yes
- [x] No

### Type of change

- [x] Bug fix (change which fixes an issue)

### Tested on

- [ ] iOS
- [ ] Android

### Related issues

#1310 #1325

### Checklist

- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings

---------

Co-authored-by: Cuc Dan Mihai <danchily@gmail.com>
Co-authored-by: Cuc Dan Mihai <dan-mihai.cuc@visma.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Injun Choi <80089617+injunchoi98@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug fix PRs that are fixing bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants