Skip to content

feat(go): enforce required field presence in UnmarshalJSON - #6495

Draft
Fluf22 wants to merge 4 commits into
mainfrom
feat/go-enforce-requirements
Draft

feat(go): enforce required field presence in UnmarshalJSON#6495
Fluf22 wants to merge 4 commits into
mainfrom
feat/go-enforce-requirements

Conversation

@Fluf22

@Fluf22 Fluf22 commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Context

Stacked on top of #6494 (case-sensitive JSON key matching fix).

Problem

Go's UnmarshalJSON for models with additionalProperties silently accepts missing required fields, leaving them at their zero value (e.g. "" for objectID). This is inconsistent with 5 of our other client languages.

Current behavior across languages

Language Missing required field Behavior
Python Hard fail Pydantic ValidationError
Swift Hard fail DecodingError thrown
Kotlin Hard fail NoSuchElementException
Dart Hard fail Exception thrown
Scala Hard fail Extraction fails
Java Silent Field set to null
Ruby Silent Field set to nil
PHP Silent Field not set, manual validation
JavaScript Silent undefined
Go (before) Silent Zero value ("", 0, etc.)

Solution

In the UnmarshalJSON template, required fields now return an error when their exact JSON key is absent:

if v, ok := raw["objectID"]; ok {
    // decode...
} else {
    return fmt.Errorf("required field objectID not found in Hit")
}

Optional fields remain unchanged — missing keys are silently accepted.

Affected models

~11 models with additionalProperties + required fields, including:

  • search/Hit, composition/Hit, recommend/RecommendHit (objectID)
  • search/SearchResponse (~35 fields, many required)
  • search/SearchSynonymsResponse (hits, nbHits)
  • search/DictionaryEntry (objectID)
  • ingestion/PushTaskRecords (objectID)

Checklist

  • Template change in templates/go/model_simple.mustache
  • Regenerate Go clients: yarn cli generate go
  • Run CTS: yarn cli cts run go
  • Verify no CTS regressions from stricter validation

Fluf22 added 4 commits June 10, 2026 15:12
Go's encoding/json performs case-insensitive field matching during
Unmarshal. This causes data corruption when a customer record has a
property whose name differs from a reserved field only by casing
(e.g. 'ObjectID' vs 'objectID'):
- If the customer's property is a string, it silently overwrites the
  reserved field value (data loss)
- If it is a non-string type, Unmarshal fails with a type error (crash)

Fix: rewrite the UnmarshalJSON template for models with
additionalProperties to parse into a raw map[string]json.RawMessage
first, then extract known fields by exact (case-sensitive) key match.
Remaining keys are preserved as additional properties with their
original casing and types.

This affects all Go models with additionalProperties: Hit,
RecommendHit, composition Hit, and others.

Requires regeneration: yarn cli generate go
The type alias was only needed by the old UnmarshalJSON approach that
used json.Unmarshal into the alias to avoid recursive unmarshalling.
The new raw-map-based UnmarshalJSON no longer needs it.
Required fields now return an error when absent from the JSON payload
instead of silently accepting the zero value. This aligns Go with
Python, Swift, Kotlin, Dart, and Scala which all hard-fail on missing
required fields.
@algolia-api-clients-automation-bot

algolia-api-clients-automation-bot Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

✔️ Code generated!

Name Link
🪓 Triggered by 7b1263988163ab13372ea6852da5fdf0e06a5a4c
🍃 Generated commit 9f4020333408fee0fd183282a9e127d768a4b91d
🌲 Generated branch generated/feat/go-enforce-requirements
📊 Benchmark results

Benchmarks performed on the method using a mock server, the results might not reflect the real-world performance.

Language Req/s
go 1795

@Fluf22
Fluf22 force-pushed the fix/go-object-id branch 2 times, most recently from ac413df to f2446ff Compare June 11, 2026 20:42
Base automatically changed from fix/go-object-id to main June 11, 2026 20:54
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