fix(closes OPEN-10343): handle Google ADK callback exceptions cleanly#638
Merged
gustavocidornelas merged 1 commit intomainfrom May 7, 2026
Conversation
46b7e9d to
31aacc1
Compare
31aacc1 to
1771fb0
Compare
When a user-defined `before_model_callback` raises (e.g. a guardrail
short-circuit), the Openlayer tracer used to surface a chained
`ValueError("<Token> was created in a different Context")` from its
contextvar cleanup paths and overwrite span output with `"Error: ..."`,
polluting tracebacks and traces. Make exception unwinding boring:
- Add `_safe_reset_contextvar`: wraps `ContextVar.reset(token)` with the
same `try/except ValueError` pattern used by `tracer.create_step`, so
cross-context tokens during async unwind no longer raise a chained
exception. Apply it to the three bare reset sites in the agent
transfer-token path, async callback wrapper, and sync callback wrapper.
- Add `_record_step_error`: stores `metadata["error"] = {type, message}`
on the step instead of overwriting `step.output` with `"Error: ..."`.
Apply it to all five wrappers (agent, LLM, tool, async/sync callback).
- Demote the three pass-through `logger.error("Error in ...")` lines to
`logger.debug` — the exception already shows up in the user's
traceback, our duplicate log only added confusion.
- Add `tests/test_google_adk_integration.py` with end-to-end coverage
asserting the user's exception is the sole exception in the chain,
that metadata records the error, and that `step.output` is not
overwritten — plus unit tests for the new helpers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1771fb0 to
d46d48e
Compare
gustavocidornelas
approved these changes
May 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a user-defined
before_model_callbackraises (e.g. a guardrail short-circuit), the Openlayer Google ADK tracer used to:ValueError("<Token> was created in a different Context")from its contextvar cleanup paths during async exception unwinding, polluting the user's traceback.step.outputwith a"Error: ..."string, polluting traces.logger.error("Error in agent execution: ...")/Error in LLM call/Error in tool execution, which duplicated the user's exception in the output.This change makes exception unwinding boring:
_safe_reset_contextvarlifted intolib/tracing/tracer.pyas a shared helper. WrapsContextVar.reset(token)with the same cross-contextValueErrorswallow thattracer.create_stepalready used inline. Applied at the three bare reset sites ingoogle_adk_tracer.py(agent transfer-token, async/sync callback wrappers) — these were the actual chain producers — and at the previously-inline site increate_step._record_step_erroringoogle_adk_tracer.pyrecordsstep.metadata["error"] = {"type", "message"}instead of overwritingstep.output. Applied to all five wrappers (agent / LLM / tool / async + sync callback).logger.error("Error in ...")lines demoted tologger.debug— the exception already shows in the user's traceback.tests/test_google_adk_integration.py(7 tests) asserts: user exception is the only entry in the chain,metadata["error"]is recorded,step.outputis not overwritten, plus unit coverage for the helpers.Test plan
tests/test_google_adk_integration.py) — 7/7 pass.test_offline_buffering.py,test_portkey_integration.py— 45/45 pass.🤖 Generated with Claude Code