Skip to main content
Applies to:
  • Plan -
  • Deployment -

Summary

Issue: When multiple generateText calls share a single wrapAISDK-instrumented model instance and run concurrently, doGenerate child spans show inputs and outputs from the wrong parent generateText span. Cause: wrapAISDK patches the model object’s doGenerate method in place, closing over the first call’s parent span; the AUTO_PATCHED_MODEL guard prevents re-patching on subsequent concurrent calls, so all parallel doGenerate invocations log into the first call’s span. Resolution: Construct a fresh model instance inside each task function instead of sharing a single module-scoped instance.

Resolution steps

If using a shared model instance across parallel tasks

Step 1: Move model construction inside the task function

Replace any module-scoped model singleton with a per-call factory so each generateText call patches its own instance. Before (triggers bug):
After (workaround):

Step 2: Verify span parenting in the Braintrust UI

For each top-level generateText span, expand its doGenerate child and confirm that input.messages contains the same content as the parent span’s input. Each doGenerate span should be parented under its own generateText span.

Otherwise, if using Eval with parallel task execution

Step 1: Construct the model inside the task function

Reproduction script

The following script can be used to reproduce the problem. Set USE_FACTORY_WORKAROUND=true to enable the workaround:
Note: This is a known bug in wrapAISDK. A permanent fix (resolving parent spans via async-context tracking instead of a closed-over span) has not yet been released. The per-task model instance pattern is the recommended workaround until a patched SDK version is available.