MetaMask / MetaMask/metamask-mobile
TypeError: c.connector.getChild is not a function in dApp browser when site calls wallet_signTypedData_v4
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 3k
- Forks
- 1.7k
- Avg merge
- 1d 14h
- Merged PRs (30d)
- 669
Description
## Summary
When a dApp running inside MetaMask Mobile's in-app dApp browser calls `wallet_signTypedData_v4` via wagmi (`useSignTypedData().signTypedDataAsync(...)`) on the injected provider, MetaMask Mobile throws:
```
TypeError: c.connector.getChild is not a function
```
The error fires AFTER `eth_requestAccounts` resolves successfully (we get the address) and BEFORE the typed-data prompt is shown to the user. As a result the sign-in step never starts and the user is stuck on the connect/login modal with no signing prompt.
This is reproducible on every MetaMask Mobile in-app browser session for our app (Persian/Farsi marketplace on Polygon mainnet). Desktop MetaMask extension is unaffected. Other mobile wallets via WalletConnect (Trust, OKX, Rainbow) are unaffected. The fault triggers only on the **injected** provider exposed by MetaMask Mobile's dApp browser webview.
`getChild` is not a method that exists on the wagmi/Reown injected connector — see "Evidence" below. Static greps confirm the throwing line is **inside MetaMask Mobile's own injected provider script**, not in the dApp bundle.
## Reproduction
**Stack:**
- `@reown/appkit ^1.8.12`
- `@reown/appkit-adapter-wagmi ^1.8.12`
- `wagmi ^2.19.0`
- `viem ^2.x`
- `@wagmi/connectors ^6.2.0`
- Next.js 16 (App Router) + React 19
**Steps:**
1. Open MetaMask Mobile's in-app dApp browser on iOS or Android.
2. Navigate to a dApp using the stack above.
3. Tap "Connect"; AppKit modal opens. Tap "MetaMask" (injected option).
4. `eth_requestAccounts` resolves → wagmi has the address, wallet shows as connected.
5. The dApp now calls `signTypedDataAsync(typeData)` (EIP-712, simple 2-field message — wallet/nickname strings, no nested types):
```ts
const typeData = {
types: { Arandao: [
{ name: "wallet", type: "string" },
{ name: "nickname", type: "string" },
]},
primaryType: "Arandao" as const,
domain: { name: "AranDao.xyz", version: "1", chainId: 137 },
message: { wallet: "0x...", nickname: "..." },
};
const signature = await signTypedDataAsync(typeData);
```
6. **Expected:** MetaMask Mobile shows the typed-data prompt; user approves; signature is returned.
7. **Actual:** Console logs `TypeError: c.connector.getChild is not a function`. No typed-data prompt is rendered. The promise rejects with this TypeError. Login flow halts.
**Reproduction rate:** 100% on MetaMask Mobile in-app browser. 0% on every other tested wallet path.
## Evidence — `getChild` is NOT in the dApp bundle
We searched every dependency that runs inside the WebView during the affected flow:
| Search target | Result |
|---|---|
| `getChild` in `node_modules/@reown/*` (`appkit`, `appkit-adapter-wagmi`, `appkit-controllers`, `appkit-utils`, `appkit-scaffold-ui`, `appkit-ui`, `appkit-common`, `appkit-pay`, `appkit-polyfills`, `appkit-wallet`) | **0 matches** |
| `getChild` in `node_modules/wagmi` and `node_modules/@wagmi/*` | **0 matches** |
| `getChild` in `node_modules/viem` | **0 matches** |
| `getChild` in our application source (`src/`) | **0 matches** |
| `getChild` in `node_modules/@sentry/*` | only `getChildRoutesRecursively` in `@sentry/react/.../reactrouter-compat-utils/instrumentation.js` — wrong shape (function, not method on `connector`); React Router instrumentation, not loaded on Next.js App Router |
| `getChild` in `node_modules/next/*` | only `@vercel/og` (yoga-layout, server-side image generation, never runs in mobile webview) |
The minified `c.connector.getChild(...)` call site does NOT exist in any client-side JavaScript we ship. The throwing line therefore originates inside **MetaMask Mobile's own injected provider script** — the wrapper MetaMask Mobile injects around `window.ethereum` to bridge the in-app webview ↔ native wallet.
Most likely cause: a recent MetaMask Mobile build expects a `connector.getChild(...)` accessor on its internal connection-tree state that the WebView build no longer provides (build mismatch between native side and webview-side bridge, or a feature flag rolled out unevenly between the two).
## What our dApp does (NOT cause)
We use `@reown/appkit-adapter-wagmi` with the standard `injected()` connector from `@wagmi/connectors`. We do not subclass any connector. We do not patch `window.ethereum`. We do not intercept the provider RPC. The throw is purely in the bridge response path between MetaMask Mobile's webview and the native wallet during `wallet_signTypedData_v4`.
## Impact
This breaks login (EIP-712-signed JWT) for all MetaMask Mobile in-app browser users on our dApp. Iranian retail users use MetaMask Mobile heavily — measurable user segment blocked. We are shipping a client-side mitigation today (typed error class + localized toast guiding users to Safari/Chrome + WalletConnect), but this is a workaround, not a fix.
## Environment
- **MetaMask Mobile app versions seen so far:** TBD (PM to fill)
- **Platforms:** iOS (17.x) + Android (14.x)
- **Dapp framework:** Next.js 16 (App Router) + React 19
- **AppKit:** `@reown/appkit ^1.8.12` + `@reown/appkit-adapter-wagmi ^1.8.12`
- **Wagmi/viem:** `wagmi ^2.19.0`, `viem ^2.x`, `@wagmi/connectors ^6.2.0`
- **Network:** Polygon mainnet (chain ID 137)
## Cross-link
Our internal tracking issue: https://github.com/Arandao-Com/Frontend/issues/38
## Suggested investigation
A `feature-detect` guard on the `connector.getChild` accessor in MetaMask Mobile's injected provider's `signTypedData` handler — fall back to the flat connector when `getChild` is not exposed. This would also un-break any other dApp that hits this code path.
Happy to test a debug build or share Sentry traces if useful — please ping.
Contributor 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.
Research direction
No repository file or entry point is identified. Start by reproducing wallet_signTypedData_v4 in the MetaMask Mobile injected-provider path on iOS or Android, then trace the signTypedData bridge response where connector.getChild is called. Done means typed-data signing reaches the user prompt and succeeds without breaking eth_requestAccounts; capture the MetaMask Mobile version during testing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- next.js, react-native, typescript
- Domain
- blockchain, mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100