Problem
When paymentRequiredResult is set (missing payment signature), we still create a task and pass the error into executeToolAndUpdateTask(), which immediately stores it as a completed-with-error result. The task serves no purpose — we already know the outcome before execution.
Same applies to any future pre-flight check that can be resolved synchronously.
Current flow
prepareToolCallContext() → paymentRequiredResult set
AJV validation → pass (payment fields stripped)
task created ← unnecessary
setImmediate → executeToolAndUpdateTask → immediately stores error result
Proposed fix
Return the paymentRequiredResult synchronously (like the non-task path at line ~818), skip task creation entirely. The client gets the x402 payload faster and no zombie task is created.
if (request.params.task && paymentRequiredResult) {
// No task needed — return payment error synchronously
return paymentRequiredResult;
}
Context
Discovered during #680 (task status workaround). See res/task_status_workaround.md for the full SDK limitation analysis.
Problem
When
paymentRequiredResultis set (missing payment signature), we still create a task and pass the error intoexecuteToolAndUpdateTask(), which immediately stores it as a completed-with-error result. The task serves no purpose — we already know the outcome before execution.Same applies to any future pre-flight check that can be resolved synchronously.
Current flow
Proposed fix
Return the
paymentRequiredResultsynchronously (like the non-task path at line ~818), skip task creation entirely. The client gets the x402 payload faster and no zombie task is created.Context
Discovered during #680 (task status workaround). See
res/task_status_workaround.mdfor the full SDK limitation analysis.