fix(types): use a struct shadow so Field decodes under encoding/json/v2 #6
No reviewers
Labels
No labels
area/engine
clarity/clear
enhancement
security
size/M
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
basepeak-ai/gptscript!6
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/json-v2-field"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
(*Field).UnmarshalJSONinpkg/types/prompt.gore-enteredjson.Unmarshalthrough a defined pointer type to strip its own method:encoding/json/v2resolves a marshaler method through a defined pointer type's element as well, so that conversion no longer de-methods anything:UnmarshalJSONcalls itself for every JSON object until the process dies offatal error: stack overflow.Switched to a defined struct shadow, which has no methods of its own under either implementation:
Why it matters
Go 1.27 makes
encoding/json/v2the default. BasePeak.AI's image build installs Go from the Wolfi feed unpinned, so published images have been built on 1.27 whilego.mod(go 1.26.3/toolchain go1.26.5),make testand CI all ran v1 — atoolchaindirective only forces toolchain upgrades, so it could not hold the build down.Result: images that passed lint, tests and
/api/versioncrashed at runtime the moment an agent decoded a promptFieldfrom an object. Tenantfond-dolphin-58was down for roughly 20 hours across two releases on green builds. bpai 0.87.1 papered over it withENV GOEXPERIMENT=nojsonv2; this PR is what lets that workaround be removed.Scope
type field *Fieldwas the only instance of the de-methoding-via-pointer idiom in the repo (rg '^\s*type \w+ \*\w+'). The other three custom unmarshalers were checked and are safe:Fields.UnmarshalJSONre-enters on[]Field, an unnamed slice type, which carries no methods.config.AuthConfigalready uses a struct shadow (type AuthConfig types.AuthConfig).engine.Context.UnmarshalJSONpanics by design.Verification
New tests drive the types through
json.Unmarshalrather than callingUnmarshalJSONdirectly — the existing tests call the method directly, which skips the re-entry that actually regressed.Standalone repro (decode
{"name":"request"}into atypes.Field): stack overflow on bare 1.27.1 before, clean under both after.Full
./pkg/...suite run under both toolchains: identical results, the only failures being the two pre-existing network-dependentpkg/loader/githubtests, which fail the same way onmain.