Skip to content

Fix TinyGo JSONBody[T] type-name collision - #24

Merged
pikann merged 2 commits into
masterfrom
fix/jsonbody-tinygo-collision
Aug 30, 2026
Merged

Fix TinyGo JSONBody[T] type-name collision#24
pikann merged 2 commits into
masterfrom
fix/jsonbody-tinygo-collision

Conversation

@pikann

@pikann pikann commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes Paca-AI/paca#445 ("Plugin POST requests reach the WASM guest with an empty body").

The root cause is not in the paca host runtime (verified exhaustively — the WASM memory protocol and JSON envelope marshaling are correct). It's a TinyGo compiler behavior: plugin.JSONBody[T] is generic, and TinyGo's generic-function monomorphization appears to key instantiations by T's bare type name rather than its full declaration site.

This package declared 8 locally-scoped type bodyT struct{...} types across integration.go, branches.go, and pull_requests.go — same name, different fields per handler (e.g. setToken's {Token string} vs linkRepository's {Owner, RepoName string}). TinyGo collapsed these into one shared field layout, so json.Unmarshal silently decoded most call sites against the wrong struct: fields came out zeroed with no error, indistinguishable from an empty request body.

Fix

Renamed every JSONBody[T] body type to a name unique within the package (setTokenBody, linkRepositoryBody, createBranchBody, etc.) — 8 renames across 3 files, no behavior changes otherwise.

Verification

  • Built with the exact TinyGo version CI uses (tinygo build -target=wasip1 -buildmode=c-shared, v0.41.1)
  • Drove the real compiled binary through the actual host runtime (services/api/internal/platform/plugin.Runtime), confirming req.Body arrives intact and previously-broken routes now correctly decode their fields
  • go test ./... and go vet ./... pass

Related

This same pattern (reused local type name across JSONBody[T] call sites, broken by TinyGo) was found and fixed across all first-party plugins that switched to TinyGo builds: paca-plugin-bdd, paca-plugin-checklist, paca-plugin-dashboard, paca-plugin-example, paca-plugin-time-logging, paca-plugin-webhook. plugin-sdk-go also got a non-generic JSONBodyInto helper added as a documented escape hatch going forward.

🤖 Generated with Claude Code

TinyGo's generic-function monomorphization keys plugin.JSONBody[T]
instantiations by T's bare type name rather than its full declaration
site. This package declared 8 locally-scoped `type bodyT struct{...}`
types across integration.go, branches.go, and pull_requests.go -- same
name, different fields per handler. TinyGo collapsed them into one
shared field layout, so json.Unmarshal silently decoded most call
sites against the wrong struct: fields came out zeroed with no error,
indistinguishable from an empty request body.

Renamed every JSONBody[T] body type to a name unique within the
package (e.g. setTokenBody, linkRepositoryBody). Verified by building
with the exact TinyGo version CI uses and driving the real binary
through the actual host runtime -- previously-broken routes now
correctly see their decoded fields.

Fixes Paca-AI/paca#445.
@pikann
pikann merged commit efa23f9 into master Aug 30, 2026
3 checks passed
@pikann
pikann deleted the fix/jsonbody-tinygo-collision branch August 30, 2026 16:51
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.

Plugin POST requests reach the WASM guest with an empty body

1 participant