{"id":"7ecb8721aee14630","repo":"gohugoio/hugo","slug":"received-response-for-unknown-call-id-d-wasm-mod","errorCode":null,"errorMessage":"received response for unknown call ID %d: WASM module violated the RPC protocol","messagePattern":"received response for unknown call ID (.+?): WASM module violated the RPC protocol","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/warpc/warpc.go","lineNumber":439,"sourceCode":"\tdefer d.mu.Unlock()\n\tfor _, call := range d.pending {\n\t\tcall.err = inputErr\n\t\tcall.done()\n\t}\n\n\treturn inputErr\n}\n\nfunc (d *dispatcher[Q, R]) pendingCall(id uint32) *call[Q, R] {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tc, ok := d.pending[id]\n\tif !ok {\n\t\t// The WASM module wrote a response for an ID we never sent. This means it\n\t\t// broke the RPC protocol, e.g. a corrupted stream after an error path that\n\t\t// failed to drain its input or write a response. This is a bug in the\n\t\t// module and should be reported.\n\t\tpanic(fmt.Errorf(\"received response for unknown call ID %d: WASM module violated the RPC protocol\", id))\n\t}\n\treturn c\n}\n\ntype call[Q, R any] struct {\n\trequest       Message[Q]\n\tresponse      Message[R]\n\tresponseKinds *maphelpers.ConcurrentMap[string, bool]\n\terr           error\n\tdonec         chan *call[Q, R]\n}\n\nfunc (c *call[Q, R]) handleBlob(r io.Reader) error {\n\tdest := any(c.request.Data).(DestinationProvider).GetDestination()\n\tif dest == nil {\n\t\tpanic(\"blob destination is not set\")\n\t}\n\t_, err := io.Copy(dest, r)","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/internal/warpc/warpc.go#L421-L457","documentation":"Raised in the dispatcher's response-reader goroutine (internal/warpc/warpc.go:439) when a JSON response from a WASM module carries a call ID that has no pending call in the dispatcher's map. Since IDs are assigned by Hugo and echoed by the module, an unknown ID means the module broke the request/response protocol (duplicate reply, reply after timeout cleanup, or corrupted stdout stream).","triggerScenarios":"A WASM worker writes an extra or stray response on stdout — e.g. replying twice to one request, replying to a call already removed after a timeout, or emitting non-protocol output that parses as a message with a bogus ID.","commonSituations":"Usually follows a prior \"timeout\" error (the late reply arrives after the call was abandoned); a crashed/misbehaving module after a Hugo upgrade; custom or corrupted quickjs/katex WASM binaries; interleaved stdout corruption under heavy load.","solutions":["Check the log for a preceding timeout on the same build — the late response is the follow-on symptom; address the timeout's cause.","Re-run the build; transient module hiccups don't usually recur.","Upgrade to the latest Hugo release in case of a fixed module bug.","If reproducible, file a Hugo issue including the input that triggers it — this is an internal protocol violation, not a user config error."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"unknown call ID\") {\n    // protocol violation — restart the dispatcher/pool, report as a bug, never ignore\n}","preventionTips":["This indicates a WASM module/runtime bug, not bad user input — report it upstream with the module version","Restart the dispatcher rather than continuing on a desynced protocol stream","Pin matching versions of the host and the embedded WASM modules"],"tags":["hugo","warpc","wasm","rpc","protocol","internal-error"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}