Skip to content

Fix ResponsesRequest marshaling when service_tier is omitted#300

Open
ell-hol wants to merge 4 commits into
OpenRouterTeam:mainfrom
ell-hol:fix-responses-request-default-service-tier
Open

Fix ResponsesRequest marshaling when service_tier is omitted#300
ell-hol wants to merge 4 commits into
OpenRouterTeam:mainfrom
ell-hol:fix-responses-request-default-service-tier

Conversation

@ell-hol

@ell-hol ell-hol commented Jun 20, 2026

Copy link
Copy Markdown

Summary

This fixes a local JSON serialization error when using Beta.Responses.Send without explicitly setting ServiceTier.

I found the issue while testing the Responses API streaming path with this request:

res, err := s.Beta.Responses.Send(ctx, components.ResponsesRequest{
	Input: openrouter.Pointer(
		components.CreateInputsUnionStr("Hey there"),
	),
	Model:  openrouter.Pointer("openai/gpt-4o-mini"),
	Stream: openrouter.Bool(true),
}, nil)

This failed before any HTTP request was sent:

error serializing request body: json: error calling MarshalJSON for type components.ResponsesRequest:
json: error calling MarshalJSON for type json.RawMessage:
invalid character 'a' looking for beginning of value

The same failure happens with Stream: openrouter.Bool(false), so the issue is not specific to streaming. It happens during local request serialization.

Root cause

ResponsesRequest.ServiceTier has this struct tag:

ServiceTier optionalnullable.OptionalNullable[ResponsesRequestServiceTier] `default:"auto" json:"service_tier"`

When ServiceTier is omitted, the SDK applies the default value auto.

Before this patch, the default value could fall through to:

return []byte(tagValue)

That means the default was serialized as raw JSON:

auto

But auto is not valid JSON. Since service_tier is a string-like enum, the serialized JSON value must be:

"auto"

This explains why explicitly setting ServiceTier worked:

serviceTier := components.ResponsesRequestServiceTierAuto

ServiceTier: optionalnullable.From(&serviceTier)

In that case, the enum value goes through the normal marshaling path and is correctly serialized as "auto".

Behavior before

This failed:

req := components.ResponsesRequest{
	Input: openrouter.Pointer(
		components.CreateInputsUnionStr("Hey there"),
	),
	Model:  openrouter.Pointer("openai/gpt-4o-mini"),
	Stream: openrouter.Bool(false),
}

_, err := json.Marshal(req)

with:

invalid character 'a' looking for beginning of value

Behavior after

The same request now marshals successfully.

The default service_tier is emitted as valid JSON:

{
  "input": "Hey there",
  "model": "openai/gpt-4o-mini",
  "service_tier": "auto",
  "stream": false
}

Fix

The default marshaling logic now checks whether the default tag value is already valid JSON.

If it is valid JSON, it is preserved as-is. This keeps existing defaults such as true, false, null, and numeric values working the same way.

If it is not valid JSON, it is serialized as a JSON string. This fixes string-like defaults such as auto.

Test

Added a regression test covering ResponsesRequest without an explicit ServiceTier.

go test ./models/components -run TestResponsesRequestMarshalWithoutServiceTier -v

Full test suite passes:

go test ./...

@ell-hol ell-hol force-pushed the fix-responses-request-default-service-tier branch from 19c9125 to 0a9def0 Compare June 20, 2026 09:33
perry-the-pr-reviewer[bot]

This comment was marked as outdated.

perry-the-pr-reviewer[bot]

This comment was marked as outdated.

perry-the-pr-reviewer[bot]

This comment was marked as outdated.

perry-the-pr-reviewer[bot]

This comment was marked as outdated.

@perry-the-pr-reviewer perry-the-pr-reviewer 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.

⚠️ APPROVE unavailable on this installation — the maintainer GitHub App lacks pull_requests: write on OpenRouterTeam, so the verdict below is posted as COMMENT. Event-level approval must be added out-of-band.

Perry's Review

Fixes a marshal error when ResponsesRequest.ServiceTier (an OptionalNullable enum) is left unset: the default tag value "auto" was emitted as raw bytes, which is not valid JSON. The fix calls json.Valid before using the tag value and quotes it when needed.

Verdict: ✅ LGTM

Details

Risk: 🟡 Medium — bug fix in a shared marshaling utility called by all three marshal paths; well-isolated with a regression test

CI: no checks configured

Findings: none — the fix is correct; one unresolved prior suggestion thread (companion test for other OptionalNullable[EnumType] defaults) is resolved on approval

Codex: disabled (small tier)

Research: skipped (small tier)

Security: no concerns — categories 1–8 not applicable to JSON serialization utility

Test coverage: regression test added in models/components/responsesrequest_test.go covering the exact failure path; verifies valid JSON output and that service_tier is serialized as the string "auto"

Unresolved threads: 1 open prior Perry suggestion — resolved on approval

Scope: first review (full)
Review: tier=small · model=claude-sonnet-latest · score=0.6

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.

1 participant