{"record":{"id":"a8afb0f07bfbc329","repo":"microsoft/aspire","slug":"callback-id-missing","errorCode":null,"errorMessage":"callback ID missing","messagePattern":"callback ID missing","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go","lineNumber":564,"sourceCode":"\tid := fmt.Sprintf(\"callback_%d_%d\", c.callbackCounter.Add(1), time.Now().UnixMilli())\n\tc.callbacksMu.Lock()\n\tc.callbacks[id] = callback\n\tc.callbacksMu.Unlock()\n\treturn id\n}\n\n// unregisterCallback removes a callback by ID.\nfunc (c *client) unregisterCallback(id string) bool {\n\tc.callbacksMu.Lock()\n\tdefer c.callbacksMu.Unlock()\n\t_, exists := c.callbacks[id]\n\tdelete(c.callbacks, id)\n\treturn exists\n}\n\nfunc (c *client) invokeCallback(callbackID string, args any) (any, error) {\n\tif callbackID == \"\" {\n\t\treturn nil, errors.New(\"callback ID missing\")\n\t}\n\n\tc.callbacksMu.RLock()\n\tcallback, ok := c.callbacks[callbackID]\n\tc.callbacksMu.RUnlock()\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"callback not found: %s\", callbackID)\n\t}\n\n\tvar positionalArgs []any\n\tif argsMap, ok := args.(map[string]any); ok {\n\t\tfor i := 0; ; i++ {\n\t\t\tkey := fmt.Sprintf(\"p%d\", i)\n\t\t\tif val, exists := argsMap[key]; exists {\n\t\t\t\tpositionalArgs = append(positionalArgs, wrapIfHandle(val, c))\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}","sourceCodeStart":546,"sourceCodeEnd":582,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go#L546-L582","documentation":"invokeCallback rejects a server-originated callback request whose callback ID parameter is the empty string. The client dispatches callbacks by ID from its registry; an empty ID can never be registered (registerCallback returns \"\" only for nil callbacks), so this guards against malformed JSON-RPC callback requests from the AppHost side.","triggerScenarios":"The AppHost sends a callback request whose params[0] (the callback ID string) is missing or empty — handleCallbackRequest extracts callbackID from params and calls invokeCallback, which returns this error and it is sent back as a JSON-RPC error with code -32000.","commonSituations":"Protocol/version mismatch between generated Go code and the AppHost server (server encoding callbacks in an unexpected shape); a nil Go callback was registered (registerCallback returned \"\") yet the server still references it; a DTO mutation callback invoked after its registration ID was never persisted.","solutions":["Regenerate the Go client so its transport matches the AppHost server protocol version","Ensure you never pass nil callbacks where a callback is expected — registerCallback returns \"\" for nil and the server may then invoke a nonexistent ID","Check that callback IDs returned from capability calls are preserved (not stripped) when passed back to the server via handles","File/log the raw callback request to diagnose why params[0] is empty"],"exampleFix":"// before\nbuilder.WithCallback(nil) // registers as \"\" -> server callback fails\n\n// after\nbuilder.WithCallback(func(args ...any) any {\n\t// real implementation; gets a real callback ID\n\treturn nil\n})","handlingStrategy":"type-guard","validationCode":"if callback == nil {\n\tlog.Fatal(\"callbacks must be non-nil; nil callbacks register an empty ID\")\n}","typeGuard":"func hasCallbackID(params []any) bool {\n\treturn len(params) > 0 && id, _ := params[0].(string); id != \"\"\n}","tryCatchPattern":null,"preventionTips":["Never register nil callbacks","Keep generated Go transport in sync with the AppHost server version","Preserve callback IDs returned by capability calls","Log raw server callback requests when diagnosing protocol issues"],"tags":["go","rpc","callback","protocol","malformed-request"],"backgroundTag":"unexpected-response-shape","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}