-
Notifications
You must be signed in to change notification settings - Fork 2
Add pitfall: bindgen wrapper converts opt T to T | null #141
Description
Problem
AI agents (and developers migrating from dfx) have strong prior knowledge that Candid opt T is represented as [] | [T] in TypeScript. This was the standard pattern in @dfinity/agent and dfx-generated declarations for years.
@icp-sdk/bindgen generates a wrapper class (e.g. Backend) on top of the raw declarations that converts opt T to idiomatic T | null. Since createActor returns the wrapper, not the raw actor, code that uses the old array-style pattern breaks at runtime:
// Runtime error: Cannot read properties of null (reading 'length')
const result = await backend.getNickname();
if (result.length > 0) { name = result[0]; }The runtime error gives no hint about the actual cause, making it hard to diagnose.
Why this would help agents
Agents read the binding-generation skill before writing frontend code that calls canisters. When they see opt text in a .did file, they default to prior training data which overwhelmingly uses the [] | [T] pattern. Without an explicit callout, agents consistently produce the wrong check — this happened in practice when building a simple hello-world app with getNickname : () -> (opt text) query.
With this pitfall documented, the agent sees the correct pattern at the moment it's writing the relevant code.
Proposed addition to references/binding-generation.md
opt TisT | nullin the wrapper, not[] | [T]
@icp-sdk/bindgengenerates two layers: raw declarations underdeclarations/use the standard@icp-sdk/core/candidrepresentation whereopt Tis[] | [T], and a wrapper class (e.g.Backend) that converts this to idiomaticT | null. SincecreateActorreturns the wrapper class, always useT | null:// Wrong — raw Candid style (only applies if using declarations directly) const result = await backend.getNickname(); if (result.length > 0) { name = result[0]; } // Correct — wrapper returns T | null const result = await backend.getNickname(); if (result !== null) { name = result; }
🤖 Generated with Claude Code