microsoft/typescript-go · error · Error
Error calling callback `${name}`: ${errMsg}
Error message
Error calling callback `${name}`: ${errMsg} What it means
A registered host-side callback ran but threw an exception. The channel reports the failure to the child via MSG_CALL_ERROR and then re-throws in the parent, deliberately treating a failed callback as unrecoverable to match the native libsyncrpc addon's behavior — the pending request loop aborts.
Source
Thrown at _packages/native-preview/src/api/syncChannel.ts:366
throw new Error(`no callback named \`${name}\` found`);
}
try {
const result = cb(name, payload.toString("utf-8"));
this.writeTuple(
MSG_CALL_RESPONSE,
Buffer.from(name, "utf-8"),
Buffer.from(result, "utf-8"),
);
}
catch (e: unknown) {
const errMsg = String(e instanceof Error ? e.message : e).trim();
this.writeTuple(
MSG_CALL_ERROR,
Buffer.from(name, "utf-8"),
Buffer.from(errMsg, "utf-8"),
);
throw new Error(`Error calling callback \`${name}\`: ${errMsg}`);
}
}
// ── MessagePack tuple write ─────────────────────────────────────
/**
* Write a complete [type, name, payload] tuple in as few writeSync
* calls as possible. For messages that fit in the pre-allocated
* write buffer (64 KB), everything is assembled and sent in a single
* syscall. Larger messages use two syscalls: one for the header
* portion and one for the payload data.
*/
private writeTuple(type: number, name: Buffer, payload: Buffer | Uint8Array | string): void {
const nameLen = name.length;
const payloadIsString = typeof payload === "string";
const payloadLen = payloadIsString ? Buffer.byteLength(payload, "utf-8") : payload.length;
const nameHdrSize = binHeaderSize(nameLen);
const payloadHdrSize = binHeaderSize(payloadLen);
View on GitHub (pinned to 1bcfa18d79)
Solutions
- Fix the underlying exception reported in errMsg (the message names the callback and the cause)
- Make the callback defensive: return a well-defined error value instead of throwing when the child protocol allows it
- Validate inputs (path strings) before touching fs
- If the failure is transient (EBUSY on Windows), retry the fs operation inside the callback
Example fix
// before
channel.registerCallback('readFile', (name, path) => fs.readFileSync(path, 'utf8')); // ENOENT throws
// after
channel.registerCallback('readFile', (name, path) => {
try {
return fs.readFileSync(path, 'utf8');
} catch (e) {
return ''; // or encode an error the child understands
}
}); Defensive patterns
Strategy: try-catch
Try / catch
try { channel.call('geterr', payload); } catch (e) { if (e.message.startsWith('Error calling callback')) { const cause = e.message.split(': ').slice(1).join(': '); /* fix the fs/permission cause, then restart the channel */ } throw e; } Prevention
- Never let a registered callback throw for expected conditions — return error encodings instead
- Wrap fs calls inside callbacks and surface actionable messages
- Test callbacks against missing/locked files during development
When it happens
Trigger: Any exception inside a registerCallback handler: fs.readFileSync on a missing/permission-denied path, JSON.parse of a malformed argument, or a bug in user callback code.
Common situations: Host callback doing filesystem access for the child when the file was deleted mid-session, EACCES on restricted paths, or a custom callback that assumes an argument format the child changed between versions.
Related errors
- no callback named `${name}` found
- _submodules/TypeScript does not exist; try running `git subm
- Expected version in .custom-gcl.yml
- Source file does not exist: ${src}
- Destination directory does not exist: ${dstDir}
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/9423f60ae5d0ee02.
Report an issue: GitHub.