microsoft/typescript-go · critical
unknown callback name: %s
Error message
unknown callback name: %s
What it means
The Go server panics in newCallbackFS when the client-supplied callback list contains a name outside the six supported callbacks (readFile, fileExists, directoryExists, getAccessibleEntries, realpath, writeFile). It is a hard wiring/protocol error, not a runtime condition.
Source
Thrown at internal/api/callbackfs.go:59
callbackFileExists,
callbackDirectoryExists,
callbackGetAccessibleEntries,
callbackRealpath,
callbackWriteFile:
return true
default:
return false
}
}
// newCallbackFS creates a new callbackFS wrapping the given base filesystem.
// The callbacks slice specifies which filesystem operations should be delegated
// to the client (e.g., "readFile", "fileExists").
func newCallbackFS(base vfs.FS, callbacks []string) *callbackFS {
enabled := make(map[string]bool, len(callbacks))
for _, cb := range callbacks {
if !isCallbackName(cb) {
panic("unknown callback name: " + cb)
}
enabled[cb] = true
}
return &callbackFS{
base: base,
enabledCallbacks: enabled,
}
}
// SetConnection sets the RPC connection for callbacks.
// This must be called after the transport connection is established
// but before any filesystem operations that need callbacks.
func (fs *callbackFS) SetConnection(ctx context.Context, conn Conn) {
fs.ctx = ctx
fs.conn = conn
}
// isEnabled returns true if the named callback is enabled.View on GitHub (pinned to 1bcfa18d79)
Solutions
- Use only the six documented names: readFile, fileExists, directoryExists, getAccessibleEntries, realpath, writeFile
- If adding a new callback, extend the const block AND isCallbackName in internal/api/callbackfs.go together
- Align client and server versions so the negotiated callback set matches
Example fix
// before
callbacks := []string{"readFile", "stat"} // panics: 'stat' unknown
// after
callbacks := []string{"readFile", "fileExists"} Defensive patterns
Strategy: validation
Validate before calling
var allowed = map[string]bool{"readFile":true,"fileExists":true,"directoryExists":true,"getAccessibleEntries":true,"realpath":true,"writeFile":true}
for _, cb := range callbacks {
if !allowed[cb] { log.Fatalf("unsupported callback %q", cb) }
} Type guard
func isValidCallbackName(name string) bool {
switch name {
case "readFile", "fileExists", "directoryExists", "getAccessibleEntries", "realpath", "writeFile":
return true
}
return false
} Prevention
- Never pass user-supplied strings into the callbacks slice
- When adding a callback, update isCallbackName in the same commit
- Pin client/server versions so negotiated names match
When it happens
Trigger: Passing an arbitrary string in the callbacks slice used to build callbackFS — e.g. a client or test requesting 'stat' or a renamed callback; version skew where a newer client asks for a callback an older server doesn't know.
Common situations: Developing new callback hooks and forgetting to add them to isCallbackName's switch; clients hand-crafting the initialize payload with guessed callback names.
Related errors
- CallbackFS: %s called before connection set
- -32603
- -32603
- api: failed to write panic error response: %v (original pani
- api: failed to write response: %v
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/6e6e4f51ca7b86bd.
Report an issue: GitHub.