You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Decode Unity JSON-RPC error data into typed structs instead of map[string]any #2042
The Unity JSON-RPC error data payload is typed on the C# side and untyped on the Go side, so the two halves of the same contract cannot be checked against each other.
Every key is a bare string literal, and the accessors (rpcBoolData, rpcFloatData, copyOptionalBoolField) silently fall back to the zero value on a miss.
Consequences:
Renaming a field in ServerBusyErrorData compiles cleanly on both sides and silently disables the Go branch that depended on it. runningToolName gates the compile-reattach guidance in NextActions, so the failure mode is a lost recovery hint rather than an error.
A key typo in Go is equally invisible: rpcBoolData returns false, which is a legal value.
No static analysis can relate the C# field to the Go reader, because the only thing connecting them is a string literal.
Two more untyped reads exist on the same boundary:
Decode into Go structs with json tags mirroring each JsonRpcErrorData subclass, and read fields instead of map keys. json.Unmarshal into a typed struct keeps the key names in exactly one place per side, and pointer fields preserve the NullValueHandling.Ignore optionality that the current bool? fields carry.
Worth deciding as part of the work: whether a round-trip test that feeds real Unity payloads into the Go decoder is enough to catch renames, or whether the field names should be generated from a single source shared with cli/common/clicontract.
Scope notes
Behaviour-preserving refactor. The emitted error envelope should be byte-identical for every existing payload, including the omit-when-absent behaviour of unityServerBusyEditorActivitySummary.
Unrelated to Details and NextActions on the outgoing side: those are write-only in Go product code (all assignments, all within the project runner) and are consumed by agents reading the JSON, not by another component.
Resolved by #2214 (merged into v3-beta as c915d9a). Unity JSON-RPC error data is now decoded through typed Go structs mirroring the C# DTOs, with shared contract fixtures (tests/contracts/server_busy_error_contract.json and cli_update_required_error_contract.json) verified field-by-field on both sides.
Problem
The Unity JSON-RPC error
datapayload is typed on the C# side and untyped on the Go side, so the two halves of the same contract cannot be checked against each other.C# declares a DTO per error type:
Packages/src/Editor/Infrastructure/Api/ServerBusyErrorData.csGo decodes the same payload into
map[string]anyand reads it back by string key:cli/common/errors/busy_editor_state.goEvery key is a bare string literal, and the accessors (
rpcBoolData,rpcFloatData,copyOptionalBoolField) silently fall back to the zero value on a miss.Consequences:
ServerBusyErrorDatacompiles cleanly on both sides and silently disables the Go branch that depended on it.runningToolNamegates the compile-reattach guidance inNextActions, so the failure mode is a lost recovery hint rather than an error.rpcBoolDatareturnsfalse, which is a legal value.Two more untyped reads exist on the same boundary:
cli/common/errors/error_envelope_classification.go:191—data["type"].(string)cli/common/errors/error_envelope.go:178—data["updateCommand"].(string)Suggested direction
Decode into Go structs with
jsontags mirroring eachJsonRpcErrorDatasubclass, and read fields instead of map keys.json.Unmarshalinto a typed struct keeps the key names in exactly one place per side, and pointer fields preserve theNullValueHandling.Ignoreoptionality that the currentbool?fields carry.Worth deciding as part of the work: whether a round-trip test that feeds real Unity payloads into the Go decoder is enough to catch renames, or whether the field names should be generated from a single source shared with
cli/common/clicontract.Scope notes
unityServerBusyEditorActivitySummary.DetailsandNextActionson the outgoing side: those are write-only in Go product code (all assignments, all within the project runner) and are consumed by agents reading the JSON, not by another component.runningToolName == "compile"branch above. Not a defect in that change.