microsoft/typescript-go · critical · Error
Invalid message type from child: ${this._msgType}
Error message
Invalid message type from child: ${this._msgType} What it means
Thrown by the parent side of the synchronous MessagePack RPC channel (SyncChannel) when an incoming [type, name, payload] tuple parses correctly but its type byte is neither MSG_RESPONSE nor MSG_CALL. It means the child process is speaking a different revision of the wire protocol than the JavaScript host expects.
Source
Thrown at _packages/native-preview/src/api/syncChannel.ts:324
if (this.collectTiming) {
this.lastBytesReceived = this._msgPayload.length;
}
return this._msgPayload;
}
case MSG_ERROR: {
if (methodBuf.equals(this._msgName)) {
throw new Error(this._msgPayload.toString("utf-8"));
}
throw new Error(
`name mismatch for response: expected \`${method}\`, got \`${this._msgName.toString("utf-8")}\``,
);
}
case MSG_CALL: {
this.handleCall(this._msgName.toString("utf-8"), this._msgPayload);
break;
}
default:
throw new Error(`Invalid message type from child: ${this._msgType}`);
}
}
}
// ── Callback handling ───────────────────────────────────────────
/**
* Handle an incoming MSG_CALL from the child process.
*
* After sending the error response back to the child, this method
* intentionally re-throws to abort the caller's request loop.
* A failed callback is treated as unrecoverable to match the
* behavior of the native libsyncrpc addon.
*/
private handleCall(name: string, payload: Buffer): void {
const cb = this.callbacks.get(name);
if (!cb) {
const errMsg = `unknown callback: \`${name}\`. Please make sure to register it on the JavaScript side before invoking it.`;
View on GitHub (pinned to 1bcfa18d79)
Solutions
- Rebuild or re-download the native child binary so it matches the installed @typescript/native-preview version (the package's postinstall/download step)
- Delete any stale cached tsgo binary and reinstall the package
- Check that nothing else writes into the child's stdin/stdout
- If developing the protocol, verify the MSG_* constants in syncChannel.ts and the Go child agree
Example fix
// before const channel = new SyncChannel(oldCachedChildPath, args); // after // force re-download of the child matching the host package await ensureValidCachedBinary(version); // reinstall/update @typescript/native-preview const channel = new SyncChannel(cachedBinaryPathFor(version), args);
Defensive patterns
Strategy: validation
Validate before calling
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const hostPkg = require('@typescript/native-preview/package.json').version;
// ensure the spawned child binary was produced for this host version
classert(childVersionTag === hostPkg.version, 'host/child version skew'); Try / catch
try { channel.call(/* ... */); } catch (e) { if (String(e.message).startsWith('Invalid message type from child')) { /* respawn child with matching version */ } throw e; } Prevention
- Always spawn the child via the package's own binary-resolution helper
- Pin host and child versions together in lockfiles
- Never write raw logs to the child's stdout
When it happens
Trigger: Reading a response loop iteration after the framing decoded a tuple whose first element is an unknown message type constant — typically a Go child binary built from a newer/older commit than the @typescript/native-preview JS package driving it.
Common situations: Mixed versions: a locally built tsgo child paired with an npm-installed native-preview host (or vice versa); stale child binary cached on disk after upgrading the package; protocol constants changed in a refactor.
Related errors
- Expected fixed 3-element array (0x93), received: 0x${marker.
- Expected positive fixint or uint8 marker, received: 0x${tb.t
- name mismatch for response: expected `${method}`, got `${thi
- no callback named `${name}` found
- Expected binary data (0xc4-0xc6), received: 0x${marker.toStr
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/aa35acb7e207fbc1.
Report an issue: GitHub.