Skip to content

fix(server-utils): Record LangGraph span I/O for non-MessagesAnnotation state - #23315

Open
zkasuran wants to merge 1 commit into
getsentry:developfrom
zkasuran:fix/langgraph-span-io-non-messages-state
Open

fix(server-utils): Record LangGraph span I/O for non-MessagesAnnotation state#23315
zkasuran wants to merge 1 commit into
getsentry:developfrom
zkasuran:fix/langgraph-span-io-non-messages-state

Conversation

@zkasuran

Copy link
Copy Markdown

instrumentLangGraph recorded span input and output only when the graph state uses MessagesAnnotation. The input read did args[0].messages ?? [] and the output helper returned early when result.messages was not an array, so a graph on a custom state annotation produced an empty gen_ai.input.messages and no gen_ai.response.text. No error, just an empty invoke_agent span in the AI Agents view.

This keeps the MessagesAnnotation path unchanged. When there is no messages array, it serializes the whole input and output state and records it, wrapped as a single { role, content } message so the attribute stays a valid chat array (the convention extractLLMRequestAttributes already uses in this package). A null input (the resume case) records nothing rather than a misleading empty array. Serialization uses core's circular-safe stringify so an unusual state object cannot throw inside the span callback.

Fixes #19628

AI assistance (Claude, Anthropic) was used in developing this change. The design, review and verification were done by the author. Verified locally: the @sentry/server-utils vitest suite (335 to 339 passing), the new tests failing before and passing after the fix, oxlint --type-aware, oxfmt --check, tsc on the changed files, plus a real Google Gemini LangGraph run showing the span input and output empty before and populated after.

…on state

instrumentCompiledGraphInvoke read the graph input and output through
`args[0].messages` and `result.messages`. Those keys only exist for graphs
built on MessagesAnnotation, so a graph with a custom state annotation had its
`invoke_agent` span input and output silently left empty with no error.

Keep the existing message path unchanged. When there is no `messages` array,
fall back to serializing the whole input and output state onto
`gen_ai.input.messages` and `gen_ai.response.text`, wrapped as a single
role/content message so the attribute stays a valid chat array (the same shape
LangChain LLM prompts already use). A null input still records nothing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@zkasuran
zkasuran requested a review from a team as a code owner August 12, 2026 06:50
@zkasuran
zkasuran requested review from logaretm and stephanie-anderson and removed request for a team August 12, 2026 06:50

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e194f28. Configure here.

} else if (inputState && typeof inputState === 'object') {
span.setAttributes({
[GEN_AI_INPUT_MESSAGES]: stringify([{ role: 'user', content: stringify(inputState) }]),
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty messages misrouted to fallback

Low Severity

inputMessages is normalized with ?? [], then the MessagesAnnotation path is chosen only when length > 0. An explicit empty messages array therefore falls through to the custom-state branch and is recorded as a synthetic user message wrapping the whole input object. That diverges from the output helper, which uses Array.isArray and keeps empty messages on the chat path, and changes prior MessagesAnnotation behavior for empty inputs.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e194f28. Configure here.

@nicohrubec
nicohrubec requested review from nicohrubec and removed request for stephanie-anderson August 12, 2026 08:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

instrumentLangGraph input/output recording only works with MessagesAnnotation

1 participant