Bug description
ResumeWithInterceptor can leave the coroutine span event opened on a ChildTrace when another async integration changes the AsyncContext's current trace while BaseContinuationImpl.resumeWith(...) is executing.
AsyncContextSpanEventSimpleAroundInterceptor.before() obtains a trace with continueAsyncTraceObject(...) and starts a span event. Its after() resolves the trace again through currentAsyncTraceObject(). If that lookup returns null or a different trace after a nested Reactor callback, the original event is not closed. When Reactor later closes the child trace's asynchronous invocation block, Pinpoint reports a mismatched stack ID because the coroutine event is still on top.
Observed warning
Corrupted call stack found
PinpointException: not matched stack id. expected=1001, current=-1,
spanEvent=SpanEvent{stackId=-1, serviceType=8901, ...}
PinpointException: not empty call stack
PinpointException: already closed trace
The application request succeeds, but its trace can be corrupted or dropped and the agent emits repeated warning stack traces.
Environment
- Pinpoint agent: 3.1.0
- Spring WebFlux / Reactor Core: 3.8.6
- Kotlin coroutines: 1.11.0
- JDK: 26
- Coroutine execution uses a virtual-thread dispatcher
Expected behavior
The interceptor should close the same trace block that it opened in before(), regardless of changes to the async context's current trace during the intercepted continuation.
Proposed fix
Use the block-aware async interceptor base for ResumeWithInterceptor. AsyncContextSpanEventBlockSimpleAroundInterceptor passes the exact TraceBlock returned by before() into after(), avoiding a second lookup of currentAsyncTraceObject().
I am preparing a pull request with focused regression coverage.
Bug description
ResumeWithInterceptorcan leave the coroutine span event opened on aChildTracewhen another async integration changes theAsyncContext's current trace whileBaseContinuationImpl.resumeWith(...)is executing.AsyncContextSpanEventSimpleAroundInterceptor.before()obtains a trace withcontinueAsyncTraceObject(...)and starts a span event. Itsafter()resolves the trace again throughcurrentAsyncTraceObject(). If that lookup returnsnullor a different trace after a nested Reactor callback, the original event is not closed. When Reactor later closes the child trace's asynchronous invocation block, Pinpoint reports a mismatched stack ID because the coroutine event is still on top.Observed warning
The application request succeeds, but its trace can be corrupted or dropped and the agent emits repeated warning stack traces.
Environment
Expected behavior
The interceptor should close the same trace block that it opened in
before(), regardless of changes to the async context's current trace during the intercepted continuation.Proposed fix
Use the block-aware async interceptor base for
ResumeWithInterceptor.AsyncContextSpanEventBlockSimpleAroundInterceptorpasses the exactTraceBlockreturned bybefore()intoafter(), avoiding a second lookup ofcurrentAsyncTraceObject().I am preparing a pull request with focused regression coverage.