Skip to content

Fix ResponsesRequest marshaling when service_tier is omitted#300

Open
ell-hol wants to merge 2 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 2 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 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 is not
configured, so the verdict below is posted as COMMENT. Event-level approval
(for branch-protection / review requirements) must be added out-of-band.

Perry's Review

Fixes invalid JSON marshaling for ResponsesRequest.ServiceTier: when the field is unset, the default:"auto" tag now correctly produces "auto" (quoted) rather than bare auto (invalid JSON).

Verdict: ✅ LGTM

Details

Risk: 🟢 Low

CI: no checks recorded (0 checks)

Findings: none

Security: no concerns

Test coverage: new test TestResponsesRequestMarshalWithoutServiceTier directly exercises the fixed path — constructs ResponsesRequest without ServiceTier, marshals, verifies both json.Valid and presence of "service_tier":"auto". Only one other OptionalNullable[EnumType] with a string default: tag exists in the codebase (ResponsesRequest.ServiceTier) and it is covered.

Unresolved threads: 1 prior Perry suggestion (companion test for ChatRequest.ServiceTier) — field is *ChatRequestServiceTier (plain pointer), already handled by the Kind==String branch; suggestion stands as optional documentation.

Scope: first review (full)

Review: tier=small · model=claude-sonnet-latest · score=?

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