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
- Read the appended <message> portion to identify the original failure and fix the callback code that threw.
- Add defensive validation of the args object inside the callback before using nested properties.
- Wrap risky operations inside the callback so full stack traces and custom error types are preserved/logged.
- 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
- Validate args shape at the top of every callback.
- Avoid throwing inside callbacks for control flow; return structured error results when possible.
- Log errors inside callbacks so full stacks survive the message-only wrapper.
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
- Callback not found
- A ConfigureRadiusInfrastructure callback changed the value…
- Argument ' ' passed to capability ' ' contains a circular…
- Argument ' ' passed to capability ' ' is a Promise-like…
- ASPIRE_REMOTE_APPHOST_TOKEN environment variable is not set.
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)