⚠️ Alpha · testnets only. ChainRender is in active alpha and deployed on testnets only — Ethereum Sepolia, the Robinhood Chain Testnet, and the Circle Arc Testnet — not on any mainnet. Contracts, addresses, and APIs may change. Do not use with real funds or production assets.
Resources

Troubleshooting

Symptom → likely cause → fix. If your app isn't behaving as expected, find the symptom here first.

Rendering

The render is blank / empty. Likely the app hash isn't registered, or you're calling the wrong render router. Check ComponentRegistry.exists(hash) returns true, and that your deployment's router address is correct.

A data value shows "unavailable." The bound resolver reverted, is missing, ran out of gas, or doesn't support the requested kind. This is fail-closed working correctly — the app refused to fabricate a value. Check the resolver address, that it supportsKind your kind, and that its own read isn't reverting.

A slot always shows its fallback text, even though the resolver and kind are right. The arg is probably encoded the wrong way. Each kind decodes its args in one exact shape — abi.encode of the listed args, or raw bytes when the kind is marked packed. ensName, for example, takes exactly the 20 address bytes; a 32-byte abi.encode(address) or a namehash reverts "bad args" and the slot falls back. Check the kind on All Resolver Kinds and use the SDK encoder where one exists (kinds.ens.encodeNameArgs).

A role, direction, variant or other setting I wrote isn't in the render. compile() silently drops a value that isn't in the dictionary (role: "note", direction: "vertical") and any field it doesn't read — the tree still compiles. Run checkNode(tree) (SDK 0.10.0+, or the MCP chainrender_check_node tool): it lists each dropped field with its path. Allowed values are on Node Fields.

u8 out of range: undefined when compiling. A node has a type the compiler doesn't have — most often "heading". A heading is { "type": "text", "role": "heading" } (what compose.heading() emits). checkNode reports an unknown type before you compile.

A chart renders as axes only (no data). The chart's data source is unavailable — same fail-closed behavior. Verify the IChartData source resolves.

The output looks different across RPCs. It shouldn't — rendering is deterministic. If output genuinely differs, you're likely rendering different app hashes (e.g. a stale hash on one side) or hitting different router versions. Confirm the same hash + router.

Grade

My grade dropped from A to C unexpectedly. You introduced a live/off-chain dependency. Read the grade's breakdown — it names the exact deviation. Common causes: an external image (CLIENT_FETCH), a mutable dependency, or a fetch without an on-chain fallback. Swap to an on-chain resolver to return to A.

The enforcer refused my app. Check which rail: over/under-declared capabilities (R2), an action outside the envelope (R3), a value transfer without VALUE (R4), an arbitrary {to,selector} (R5), or an unanalyzable token (I5). The rejection message names it. Declare precisely what you reach; never add an arbitrary-call path. → The Capability Enforcer

Theming

My theme change didn't appear. Two cases: (1) if you changed tokens but the deployed app renders an old seeded theme, you need to re-seed and point the app at the new theme id; (2) if you're using the presentation context, confirm you're calling renderComponent with the new themeId, not the plain renderComponent.

A spacing/size change had no visible effect. The value you changed may be hardcoded rather than token-driven, or you scaled a token that the visible elements don't reference. Confirm the element uses var(--cr-*). (This exact class of issue is why the token system exists.)

My theme was rejected at build. It failed an invariant — most likely a font below 12px (legibility floor) or a foreground/background pair below WCAG AA (contrast invariant). Fix the token, don't bypass the check.

Actions

The wallet transaction does the wrong thing / nothing. Confirm the action declaration (to, sig, args) matches your contract's actual function. describeAction prints the human-readable call — check it says what you expect before signing. buildActionRequest constructs exactly the declared call, so a wrong result means a wrong declaration.

Deployment

MetaMask says a chunk transaction is "likely to fail". After Glamsterdam, storing a large chunk can need more gas than the wallet will send. The visual builder sizes chunks from the chain's txGasCap and measured storageGas in chains.json (Sepolia: 45,000,000 gas, about 23.6 KB per chunk) and refuses to send a transaction above the cap. If you still see the warning, the builder you're using predates that change, or the chain has no txGasCap entry. → Size Limits & Glamsterdam

A Hardhat script fails with "fields had validation errors". Hardhat's local signer refuses any transaction above 30,000,000 gas. Keep the transaction under it, or sign it with viem directly. → Local Build Environment

npm audit reports a high-severity Zod advisory. It's GHSA-mrhx-c7xc-m3w5, reached through Hardhat 3's dependency on Zod 3, for which no patch exists. It's dev-only. Don't run npm audit fix --force (it downgrades to Hardhat 2) or override Zod to 4 (it breaks Hardhat's config validation). → Local Build Environment

My app hash changed and I didn't expect it. You changed something baked into identity — text, structure, a role, a declared action, or a baked argument (like a chart's dimensions or a resolver address in a builder). Presentation (theme/palette) is render-time and doesn't change the hash; everything else does. → Content Addressing

A viewer/client shows stale behavior after I updated something on-chain. The client may be hand-holding a copy of an ABI or address that's now out of date. Ensure your client reads its ABI and addresses from a single source (the compiled artifact / the addresses file), not a hand-maintained copy — stale duplicated references are a common integration pitfall.

Still stuck?

  • Re-read the render as bytes: decode the actual renderHash output and look at what's really there, rather than assuming. Most "impossible" render bugs are visible in one look at the real output.
  • Check the Gotchas, Do's & Don'ts — your issue may be a known pattern.

Related