{"record":{"id":"390f387fffa251db","repo":"microsoft/aspire","slug":"callback-not-found-s","errorCode":null,"errorMessage":"callback not found: %s","messagePattern":"callback not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go","lineNumber":571,"sourceCode":"// 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}\n\t\t}\n\t} else if args != nil {\n\t\tpositionalArgs = append(positionalArgs, wrapIfHandle(args, c))\n\t}\n\n\tresult := callback(positionalArgs...)\n","sourceCodeStart":553,"sourceCodeEnd":589,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go#L553-L589","documentation":"The AppHost transport multiplexes callbacks by ID. invokeCallback looks up callbackID in the registered callback map and fails if no callback with that ID is registered. This usually means the remote side referenced a callback that was never registered or has been removed.","triggerScenarios":"The AppHost invokes a callback ID that the Go side never registered (registration failed or code path skipped), or the callback was unregistered/disposed before the request arrived, or IDs diverged due to version mismatch.","commonSituations":"AppHost restarted or callback registry reset while generated proxies still reference old IDs; race where a resource is disposed while the AppHost still calls back; stale connection reusing IDs from a previous session.","solutions":["Log the unknown callbackID and compare with the IDs your code registers via the callback registration API.","Ensure callbacks are registered before the builder/connection starts serving requests.","Re-register callbacks after reconnecting; do not reuse IDs across connections.","Check that no code path disposes or overwrites the callback map entry prematurely."],"exampleFix":"// before\ncallback, ok := c.callbacks[callbackID]\n// after\nc.callbacksMu.RLock()\ncallback, ok := c.callbacks[callbackID]\nc.callbacksMu.RUnlock()\nif !ok {\n    return nil, fmt.Errorf(\"callback not found: %s (registered: %v)\", callbackID, c.registeredIDs())\n}","handlingStrategy":"try-catch","validationCode":"// ensure all callbacks are registered before serving:\nif err := transport.RegisterCallback(\"myCallback\", handler); err != nil {\n    log.Fatalf(\"callback registration failed: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"result, err := proxy.Call(ctx)\nif err != nil && strings.Contains(err.Error(), \"callback not found\") {\n    // re-register callbacks and reconnect\n    transport.Reconnect(ctx)\n}","preventionTips":["Register callbacks before the connection starts serving.","Re-register callbacks after every reconnect.","Avoid disposing resources while the AppHost may still invoke their callbacks.","Never assume callback IDs survive AppHost restarts."],"tags":["go","aspire","callback","rpc","stale-state"],"backgroundTag":"record-not-found","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"}