Skip to content

fix: send list-of-primitive multipart fields as repeated form fields (#819) - #825

Merged
kraenhansen merged 1 commit into
mainfrom
kh/fix-819-multipart-list-serialization
Jul 30, 2026
Merged

fix: send list-of-primitive multipart fields as repeated form fields (#819)#825
kraenhansen merged 1 commit into
mainfrom
kh/fix-819-multipart-list-serialization

Conversation

@kraenhansen

@kraenhansen kraenhansen commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary

Interim fix for #819. speech_to_text.convert(keyterms=[...]) (and other multipart list fields) fails with invalid_keyword_length because the whole list is sent as one JSON-array string instead of repeated form fields.

Root cause (verified): generator fern-python-sdk 4.46.9 (commit cb4feb824, PR fern-api/fern#11284, 2026-01-08) added an _is_primitive_type() gate to multipart serialization: only scalar primitives are sent directly, everything else — including List[str] — is json.dumps(jsonable_encoder(...))'d. PR #817 bumped us onto that behavior (4.42.0 → 4.64.1). The change was undocumented — it shipped bundled inside a "fix python wire tests" PR. Fixed upstream in generator 5.22.2, but that's past the 5.5.4 min-Python-3.10 clamp, so we can't just upgrade forward.

⚠️ This is a temporary patch — when to revert

This hand-edits Fern-generated files, so it must be retired once the generator itself emits the correct code. Revert (via fern replay forget <patch-id>, then regenerate) as soon as either of these is true:

  • The generator is upgraded to ≥ 5.22.2 — the version that fixes list-of-primitive multipart serialization (fix-multipart-list-of-primitives-repeated-fields.yml). ⚠️ Note: ≥ 5.5.4 raises the generated min-Python to 3.10 — only take this path once we're ready for that breaking change.
  • A 4.x backport of the 5.22.2 fix lands (requested from Fern) and we pin to it — keeps Python 3.8 support and fixes the bug, at which point this patch is fully redundant.

Until then, Fern Replay re-applies this patch on every regeneration. Leaving it in place after the generator is fixed will cause a 3-way-merge conflict (both sides changing the same lines) surfaced in the regeneration PR body — that conflict is the signal to run fern replay forget and drop this patch.

Change

Reverts the 8 list-of-primitive (List[str]) multipart fields to raw values so httpx emits repeated form fields, matching generator 5.22.2 semantics:

File Field(s)
speech_to_text/raw_client.py keyterms
dubbing/project/raw_client.py keyterms
music/raw_client.py tags
music/finetunes/raw_client.py tags
studio/projects/raw_client.py genres, pronunciation_dictionary_locators, voice_settings
audio_native/raw_client.py pronunciation_dictionary_locators

Object fields (labels, entity_detection, entity_redaction, webhook_metadata) keep json.dumps — correct for multipart. Now-unused json / jsonable_encoder imports removed.

Durability

These are generated files, so the edit is carried across regenerations by Fern Replay (auto-captured as a patch in .fern/replay.lock). See the revert conditions above for how it is retired.

Test plan

  • ruff@0.11.5 (E/F/I) passes on all 6 files
  • py_compile passes on all 6 files
  • Verify speech_to_text.convert(keyterms=[...]) no longer returns invalid_keyword_length against the live API
  • Confirm Fern Replay captures the patch on the next regeneration (patches detected: 1)

Fixes #819

🤖 Generated with Claude Code

…819)

Interim hotfix for the v2.59.0 regression introduced by generator
fern-python-sdk 4.46.9 (commit cb4feb824, PR fern-api/fern#11284), which
began serializing every non-scalar multipart form field via
json.dumps(jsonable_encoder(...)). List[str] fields are not scalar
primitives, so they were sent as a single JSON-array string instead of
repeated form fields -- causing the API to validate the whole array
against per-item limits (e.g. speech_to_text keyterms ->
invalid_keyword_length).

Reverts the 8 list-of-primitive fields to raw values so httpx emits
repeated form fields, matching generator fix 5.22.2. Object fields
(labels, entity_detection, entity_redaction, webhook_metadata) keep
json.dumps. Removes now-unused json / jsonable_encoder imports.

This is intended to be carried across regenerations by Fern Replay and
retired (`fern replay forget`) once the 4.x backport of 5.22.2 lands.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kraenhansen
kraenhansen requested a review from PaulAsjes July 29, 2026 20:17
@kraenhansen kraenhansen self-assigned this Jul 29, 2026
@kraenhansen
kraenhansen merged commit 560b893 into main Jul 30, 2026
4 checks passed
@kraenhansen
kraenhansen deleted the kh/fix-819-multipart-list-serialization branch July 30, 2026 07:49
kraenhansen pushed a commit that referenced this pull request Jul 30, 2026
* [fern-generated] Update SDK

Generated by Fern
CLI Version: unknown
Generators:
  - fernapi/fern-python-sdk: 4.64.1

* [fern-replay] Applied customizations

Patches applied (1):
  - patch-560b8934: fix: send list-of-primitive multipart fields as repeated form fields (#819) (#825)

Patches with unresolved conflicts (1):
  - patch-1b45413e: [Speech Engine] Add disable_auth parameter (#806)
    Run `fern-replay resolve` to apply these customizations.

---------

Co-authored-by: fern-api[bot] <115122769+fern-api[bot]@users.noreply.github.com>
kraenhansen added a commit that referenced this pull request Jul 30, 2026
…#828)

patch-1b45413e was captured from "[Speech Engine] Add disable_auth
parameter (#806)", but its remaining diff is only a hardcoded version
bump (2.55.0 to 2.56.0) plus websockets >=13.0 (now native via the
generator config). Because it pins an old version string, it collided
with the version line on every regeneration and surfaced as an
unresolved conflict (most recently in the v2.60.0 regen PR #826).

Running `fern replay forget patch-1b45413e` drops it from the active
patch set and tombstones its content hash so it is not re-captured.
The #825 multipart fix (patch-560b8934) is unaffected, and disable_auth
itself is generated from the spec and does not depend on this patch.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.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.

keyterms parameter causes invalid_keyword_length error in v2.59.0 due to json.dumps() serialization regression

2 participants