MetaMask / MetaMask/metamask-mobile

TypeError: c.connector.getChild is not a function in dApp browser when site calls wallet_signTypedData_v4

Open
#29,639 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

external-contributor INVALID-ISSUE-TEMPLATE
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.