microsoft/aspire · error
callback not found
Error message
callback not found: %s
What it means
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.
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.
Example fix
// before
callback, ok := c.callbacks[callbackID]
// after
c.callbacksMu.RLock()
callback, ok := c.callbacks[callbackID]
c.callbacksMu.RUnlock()
if !ok {
return nil, fmt.Errorf("callback not found: %s (registered: %v)", callbackID, c.registeredIDs())
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure all callbacks are registered before serving:
if err := transport.RegisterCallback("myCallback", handler); err != nil {
log.Fatalf("callback registration failed: %v", err)
} Try / catch
result, err := proxy.Call(ctx)
if err != nil && strings.Contains(err.Error(), "callback not found") {
// re-register callbacks and reconnect
transport.Reconnect(ctx)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- callback ID missing
- -32000
- aspire: dict getter returned unexpected type %T
- aspire: dict.toObject: unexpected result type %T
- aspire: list getter returned unexpected type %T
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/390f387fffa251db.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go:571
// unregisterCallback removes a callback by ID.
func (c *client) unregisterCallback(id string) bool {
c.callbacksMu.Lock()
defer c.callbacksMu.Unlock()
_, exists := c.callbacks[id]
delete(c.callbacks, id)
return exists
}
func (c *client) invokeCallback(callbackID string, args any) (any, error) {
if callbackID == "" {
return nil, errors.New("callback ID missing")
}
c.callbacksMu.RLock()
callback, ok := c.callbacks[callbackID]
c.callbacksMu.RUnlock()
if !ok {
return nil, fmt.Errorf("callback not found: %s", callbackID)
}
var positionalArgs []any
if argsMap, ok := args.(map[string]any); ok {
for i := 0; ; i++ {
key := fmt.Sprintf("p%d", i)
if val, exists := argsMap[key]; exists {
positionalArgs = append(positionalArgs, wrapIfHandle(val, c))
} else {
break
}
}
} else if args != nil {
positionalArgs = append(positionalArgs, wrapIfHandle(args, c))
}
result := callback(positionalArgs...)
View on GitHub (pinned to 25830f84bd)