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

  1. Log the unknown callbackID and compare with the IDs your code registers via the callback registration API.
  2. Ensure callbacks are registered before the builder/connection starts serving requests.
  3. Re-register callbacks after reconnecting; do not reuse IDs across connections.
  4. 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

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


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)