Skip to content

fix: handle malformed request inputs in GenAI extractors - #866

Merged
lmolkova merged 16 commits into
open-telemetry:mainfrom
sangkyoonnam:fix/bedrock-request-extraction-errors
Oct 16, 2026
Merged

lmolkova merged 16 commits into
open-telemetry:mainfrom
sangkyoonnam:fix/bedrock-request-extraction-errors

Conversation

@sangkyoonnam

@sangkyoonnam sangkyoonnam commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Description

Fixes request extraction in bedrock, openai, anthropic, portkey and google-genai that raised on malformed input, so the request reaches the SDK and the SDK returns its own error. Each fix sits at the line that raised and uses a type check, safe field access or narrowly guarded numeric conversion: a Converse document.format that isn't a string, chat messages=None, a Responses or interactions.create input item whose type isn't a string, an Anthropic message without role or a system list of plain strings, Portkey sampling or token parameters that don't convert to numbers, and generate_content with contents of None or an empty list.

Known gaps: this covers the listed extraction failures; other malformed input paths and objects whose __str__ raises are out of scope.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How has this been tested?

Regression cases pass on this branch and fail against upstream/main source. tox latest and oldest for the five packages, plus typecheck.

Checklist

  • Followed the style guidelines of this project
  • Changelog updated if the change requires an entry
  • Unit tests added

@sangkyoonnam
sangkyoonnam requested a review from a team as a code owner October 9, 2026 07:07
Copilot AI balanced review requested due to automatic review settings October 9, 2026 07:08
@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Pull request dashboard status

Merged · refreshed 2026-10-16 15:55 UTC

Status above doesn't look right?
  • Anything look wrong? Report it with what you expected; it helps us improve the dashboard.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation preserves SDK exceptions and invocation finalization with comprehensive regression coverage.

0 open findings

What changed in this PR

Prevents Bedrock request-extraction failures from altering SDK behavior or leaving telemetry invocations unfinished.

Changes:

  • Adds guarded request extraction with debug logging.
  • Covers sync/async handlers and regression scenarios.
File Description
patch.py Safely invokes Bedrock request extractors.
tests/​test_patch.py Tests extraction failures, SDK errors, and recovery.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

BEDROCK_AGENT_RUNTIME = "bedrock-agent-runtime"


def _extract_request(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i wonder if this method can be in utils instead, and all instrumentations can be updated to use it ? I think we have the same issue in all instrumentations ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I think the same shape is elsewhere. In the OpenAI instrumentation, for example, create_chat_invocation runs before the try in patch.py, and malformed message input can raise there when content capture is enabled. I kept this one Bedrock-only on purpose: a shared helper would be new util-genai API, so I'd rather agree on the approach first. Would you prefer an issue for a util-level helper, with this PR staying as the Bedrock fix, or should I fold it in here? Either way, I'm happy to take the follow-up for the other instrumentations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lets try putting it in utils and updating all instrumentations to use it..

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Moved it to util-genai as suppress_extraction_errors(), and bedrock, openai, anthropic, portkey, google-genai and smolagents use it now. The description lists the remaining gaps.

@sangkyoonnam sangkyoonnam changed the title fix(bedrock): keep request extraction errors from failing the call fix(util-genai): keep request extraction errors from failing instrumented calls Oct 10, 2026

@lmolkova lmolkova left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please fix the extraction paths that can throw. Do not add blanket exception suppression. Extractors should handle malformed inputs defensively at the point of extraction. Instrumentation code is written in defensive way and in most cases cannot throw. Adding blanket suppression logic pollutes the code and make it impossible to understand where exceptions should be handled (in the code that calls something that can throw)

with suppress_extraction_errors():
raw_agent_id = api_params.get("agentId")
if raw_agent_id:
invocation.agent_id = str(raw_agent_id)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should not guard against arbitrary objects whose str raises where the SDK expects a string. This is outside the expected input contract, and the same kind of failure could occur anywhere, including in the exception handler or exporting pipeline

@sangkyoonnam

Copy link
Copy Markdown
Contributor Author

Thanks for the review and the direction. I'll drop suppress_extraction_errors() and fix the extraction paths that actually throw at the point of extraction, and I'll remove the __str__ guards along with their tests.

@sangkyoonnam sangkyoonnam changed the title fix(util-genai): keep request extraction errors from failing instrumented calls fix: handle malformed request inputs in GenAI extractors Oct 11, 2026
@sangkyoonnam

Copy link
Copy Markdown
Contributor Author

@lmolkova Thanks, done. I dropped suppress_extraction_errors() entirely (c126a75) and fixed each extraction path that could raise at the line that raised (e68114b, e91eed5): type checks, safe field access, and narrowly guarded numeric conversion. The __str__ guards and their tests are gone too. The description lists each case. Ready for another look.

@sangkyoonnam
sangkyoonnam requested a review from lmolkova October 12, 2026 07:40
Comment on lines +242 to +253
def _safe_float(value: Any) -> float | None:
try:
return float(value)
except (TypeError, ValueError):
return None


def _safe_int(value: Any) -> int | None:
try:
return int(value)
except (TypeError, ValueError):
return None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These still raise: float(10**400) and int(float("inf")) throw OverflowError, and float(obj) runs arbitrary __float__. Could we check types up front instead of catching, so the code can't throw (same idea as _coerce_float in google-genai interactions.py)?

Suggested change
def _safe_float(value: Any) -> float | None:
try:
return float(value)
except (TypeError, ValueError):
return None
def _safe_int(value: Any) -> int | None:
try:
return int(value)
except (TypeError, ValueError):
return None
def _as_float(value: Any) -> float | None:
if isinstance(value, float):
return value
if (
isinstance(value, int)
and not isinstance(value, bool)
and abs(value) <= sys.float_info.max
):
return float(value)
return None
def _as_int(value: Any) -> int | None:
if isinstance(value, int) and not isinstance(value, bool):
return value
return None

(needs import sys; a test case with temperature=10**400 would cover it.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Applied your suggestion in 9e48fd9 and added the 10**400 and inf cases; numeric strings are now dropped by the type check.

@sangkyoonnam

Copy link
Copy Markdown
Contributor Author

The instrumentation-genai-qwen-agent-conformance 3.14 failure is a uv download error ("I/O operation failed during extraction"), unrelated to this PR. Could someone re-run it?

@lmolkova
lmolkova added this pull request to the merge queue Oct 16, 2026
Merged via the queue into open-telemetry:main with commit ab95823 Oct 16, 2026
82 checks passed
RichardoMrMu added a commit to RichardoMrMu/opentelemetry-python-genai that referenced this pull request Oct 16, 2026
Resolve the single content conflict in tests/test_responses.py by keeping
both sides: the Responses.parse() coverage added on this branch and the
malformed-input test from open-telemetry#866 on main. Production files auto-merged;
the parse() wiring in __init__.py and response_extractors.py is intact.

Assisted-by: Doubao
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants