Skip to content

fix: lowercase bool query params on websocket connect#712

Merged
GregHolmes merged 1 commit into
mainfrom
gh/fix-websocket-bool-query-serialization
May 12, 2026
Merged

fix: lowercase bool query params on websocket connect#712
GregHolmes merged 1 commit into
mainfrom
gh/fix-websocket-bool-query-serialization

Conversation

@GregHolmes
Copy link
Copy Markdown
Contributor

Summary

Python's urllib.parse.urlencode stringifies booleans via str(), producing True/False
(capitalized). The four websocket connect methods (listen.v1, listen.v2, speak.v1,
agent.v1) all hand the encoded query dict to urlencode, so any bool kwarg — e.g.
diarize=True — reaches the API as ?diarize=True and is rejected with HTTP 400.

The generated SDK types for these params are Union[Literal["true","false"], Any] because
our AsyncAPI schemas declare them as string enums rather than type: boolean. The Any arm
lets bools pass mypy without complaint, so the bug only surfaces on the wire. HTTP raw
clients are unaffected because they hand params to httpx, which lowercases bools itself.

Fix

Add _coerce_query_value in core/query_encoder.py mapping True/False to "true"/
"false" before urlencode runs. Applied at every scalar leaf site so bools nested in
list/dict query values are also coerced. isinstance(v, bool) is precise — 1/0 are
not coerced (regression test confirms).

Not a breaking change: current behavior is "the call returns HTTP 400," so the fix can only
turn broken calls into working ones. diarize="true" (string) still works identically.

query_encoder.py is Fern-generated; the patch is frozen under the existing
"temporarily frozen — manual patches" pattern in .fernignore, with the unfreeze condition
documented in AGENTS.md.

Test plan

  • 12 new regression tests in tests/custom/test_query_encoder.py
  • Full pytest suite: 197 passed, 4 skipped, 0 failed
  • Live before/after with diarize=True against production — unpatched returned HTTP
    400 (matching the reported bug); patched opened cleanly
  • Six websocket-relevant examples completed end-to-end against production:
    13 (listen v1), 14 (listen v2), 15 (batch HTTP with diarize=True),
    21 and 24 (speak v1), 30 (agent v1)
  • ruff check clean on touched files

  urllib.parse.urlencode stringifies Python bools via str() to
  "True"/"False", which the API rejects with HTTP 400. The four
  streaming connect paths (listen v1/v2, speak v1, agent v1) all
  hit this; HTTP raw clients are unaffected because httpx
  lowercases bools itself.

  Coerce True/False to "true"/"false" in core/query_encoder.py
  before urlencode runs. Covers scalar params, list-of-scalars,
  and bools nested in dict/list query values. Freeze the file
  via .fernignore and add a regression test pinning the
  behavior at the encoder layer.
@GregHolmes GregHolmes self-assigned this May 12, 2026
@GregHolmes GregHolmes requested a review from lukeocodes as a code owner May 12, 2026 09:35
Copy link
Copy Markdown
Member

@lukeocodes lukeocodes left a comment

Choose a reason for hiding this comment

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

lgtm

@GregHolmes GregHolmes merged commit 8899609 into main May 12, 2026
10 checks passed
@GregHolmes GregHolmes deleted the gh/fix-websocket-bool-query-serialization branch May 12, 2026 09:39
GregHolmes pushed a commit that referenced this pull request May 12, 2026
🤖 I have created a release *beep* *boop*
---


##
[7.1.1](v7.1.0...v7.1.1)
(2026-05-12)


### Bug Fixes

* lowercase bool query params on websocket connect
([#712](#712))
([8899609](8899609))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

2 participants