{"record":{"id":"6e6e4f51ca7b86bd","repo":"microsoft/typescript-go","slug":"unknown-callback-name-s","errorCode":null,"errorMessage":"unknown callback name: %s","messagePattern":"unknown callback name: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/api/callbackfs.go","lineNumber":59,"sourceCode":"\t\tcallbackFileExists,\n\t\tcallbackDirectoryExists,\n\t\tcallbackGetAccessibleEntries,\n\t\tcallbackRealpath,\n\t\tcallbackWriteFile:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// newCallbackFS creates a new callbackFS wrapping the given base filesystem.\n// The callbacks slice specifies which filesystem operations should be delegated\n// to the client (e.g., \"readFile\", \"fileExists\").\nfunc newCallbackFS(base vfs.FS, callbacks []string) *callbackFS {\n\tenabled := make(map[string]bool, len(callbacks))\n\tfor _, cb := range callbacks {\n\t\tif !isCallbackName(cb) {\n\t\t\tpanic(\"unknown callback name: \" + cb)\n\t\t}\n\t\tenabled[cb] = true\n\t}\n\treturn &callbackFS{\n\t\tbase:             base,\n\t\tenabledCallbacks: enabled,\n\t}\n}\n\n// SetConnection sets the RPC connection for callbacks.\n// This must be called after the transport connection is established\n// but before any filesystem operations that need callbacks.\nfunc (fs *callbackFS) SetConnection(ctx context.Context, conn Conn) {\n\tfs.ctx = ctx\n\tfs.conn = conn\n}\n\n// isEnabled returns true if the named callback is enabled.","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/callbackfs.go#L41-L77","documentation":"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.","triggerScenarios":"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.","commonSituations":"Developing new callback hooks and forgetting to add them to isCallbackName's switch; clients hand-crafting the initialize payload with guessed callback names.","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"],"exampleFix":"// before\ncallbacks := []string{\"readFile\", \"stat\"} // panics: 'stat' unknown\n\n// after\ncallbacks := []string{\"readFile\", \"fileExists\"}","handlingStrategy":"validation","validationCode":"var allowed = map[string]bool{\"readFile\":true,\"fileExists\":true,\"directoryExists\":true,\"getAccessibleEntries\":true,\"realpath\":true,\"writeFile\":true}\nfor _, cb := range callbacks {\n    if !allowed[cb] { log.Fatalf(\"unsupported callback %q\", cb) }\n}","typeGuard":"func isValidCallbackName(name string) bool {\n    switch name {\n    case \"readFile\", \"fileExists\", \"directoryExists\", \"getAccessibleEntries\", \"realpath\", \"writeFile\":\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["go","panic","callbacks","protocol"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}