microsoft/aspire · error · Error

Callback execution failed

Error message

Callback execution failed: ${message}

What it means

The invokeCallback request handler wraps the user callback invocation in try-catch; if the callback itself throws (or its returned promise rejects), the error message is captured and rethrown as 'Callback execution failed: <message>'. It preserves the original message but not the original stack/type.

Solutions

  1. Read the appended <message> portion to identify the original failure and fix the callback code that threw.
  2. Add defensive validation of the args object inside the callback before using nested properties.
  3. Wrap risky operations inside the callback so full stack traces and custom error types are preserved/logged.
  4. If the message indicates a transport-level failure, verify the connection stayed open during callback execution.

Example fix

// before
client.registerCallback('id', async (args) => {
  return JSON.parse(args.payload).value; // throws if payload is undefined
});

// after
client.registerCallback('id', async (args) => {
  if (!args?.payload) throw new Error(`payload missing for callback 'id'`);
  return JSON.parse(args.payload).value;
});
Defensive patterns

Strategy: try-catch

Validate before calling

if (!args || typeof args !== 'object') {
  throw new Error(`invalid callback args: ${JSON.stringify(args)}`);
}

Type guard

function hasPayload(args: unknown): args is { payload: string } {
  return typeof args === 'object' && args !== null && 'payload' in args;
}

Try / catch

try {
  return await callback(args, client);
} catch (error) {
  console.error('callback failed:', error); // preserve original before wrapping
  throw error;
}

Prevention

When it happens

Trigger: Any user-registered callback invoked by the .NET side throws synchronously or rejects: unhandled null arguments, failed deserialize of args, thrown application logic, or an inner await rejecting inside the callback body.

Common situations: Callback logic assumes a field exists in args; database/network call inside callback fails; bug in wrapper-generated unpacking; error thrown by a nested handle method invoked inside the callback.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/a97e252d9db96f40. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/transport.mts:956

                    this.connection.onClose(() => {
                        this.connection = null;
                    });
                    this.connection.onError((err: any) => console.error('JsonRpc connection error:', err));

                    // Handle callback invocations from the .NET side
                    this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => {
                        const callback = callbackRegistry.get(callbackId);
                        if (!callback) {
                            throw new Error(`Callback not found: ${callbackId}`);
                        }
                        try {
                            // The registered wrapper handles arg unpacking and handle wrapping
                            // Pass this client so handles can be wrapped with typed wrapper classes
                            return await Promise.resolve(callback(args, this));
                        } catch (error) {
                            const message = error instanceof Error ? error.message : String(error);
                            throw new Error(`Callback execution failed: ${message}`);
                        }
                    });

                    socket.on('error', onConnectedSocketError);
                    socket.on('close', onConnectedSocketClose);

                    const authToken = process.env.ASPIRE_REMOTE_APPHOST_TOKEN;
                    if (!authToken) {
                        throw new Error('ASPIRE_REMOTE_APPHOST_TOKEN environment variable is not set.');
                    }
                    this.connection.listen();
                    const authenticated = await this.connection.sendRequest<boolean>('authenticate', authToken);
                    if (!authenticated) {
                        throw new Error('Failed to authenticate to the AppHost server.');
                    }

                    connectedClients.add(this);
                    this._connectPromise = null;

View on GitHub (pinned to 25830f84bd)