{"record":{"id":"35877c8338444f70","repo":"wavetermdev/waveterm","slug":"waveid-is-required","errorCode":null,"errorMessage":"waveid is required","messagePattern":"waveid is required","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"tsunami/engine/serverhandlers.go","lineNumber":424,"sourceCode":"\n\tif r.Method != http.MethodPost {\n\t\thttp.Error(w, \"method not allowed\", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\n\tbody, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"failed to read request body: %v\", err), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tvar event vdom.VDomEvent\n\tif err := json.Unmarshal(body, &event); err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"failed to parse JSON: %v\", err), http.StatusBadRequest)\n\t\treturn\n\t}\n\tif strings.TrimSpace(event.WaveId) == \"\" {\n\t\thttp.Error(w, \"waveid is required\", http.StatusBadRequest)\n\t\treturn\n\t}\n\tif event.TermInput == nil {\n\t\thttp.Error(w, \"terminput is required\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\th.renderLock.Lock()\n\th.Client.Root.Event(event, h.Client.GlobalEventHandler)\n\th.renderLock.Unlock()\n\n\tw.WriteHeader(http.StatusNoContent)\n}\n\nfunc (h *httpHandlers) handleDynContent(w http.ResponseWriter, r *http.Request) {\n\tdefer func() {\n\t\tpanicErr := util.PanicHandler(\"handleDynContent\", recover())\n\t\tif panicErr != nil {","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/tsunami/engine/serverhandlers.go#L406-L442","documentation":"handleTermInput requires the parsed VDomEvent to carry a non-blank WaveId identifying which wave/block the terminal input targets. If event.WaveId is empty or whitespace-only after TrimSpace, it returns 400 'waveid is required'.","triggerScenarios":"POSTing a JSON event whose waveId field is missing, null, empty string, or only whitespace; constructing VDomEvent programmatically without setting WaveId.","commonSituations":"Scripts replaying events from logs where waveId was stripped; frontend bugs not binding the active wave id; template payloads with placeholder values left empty.","solutions":["Set the waveId field in the JSON payload to the target wave's id","Check the client that produces the event actually propagates the current wave id","Use the wave id shown in the running session rather than a hardcoded placeholder","Add a client-side assertion on waveId before POSTing"],"exampleFix":"// before\n{\"termInput\":{\"inputData\":\"ls\\n\"}}\n// after\n{\"waveId\":\"wave-1234-abcd\",\"termInput\":{\"inputData\":\"ls\\n\"}}","handlingStrategy":"validation","validationCode":"if (!event.waveId || !event.waveId.trim()) {\n  throw new Error('waveid is required: set event.waveId before POSTing')\n}","typeGuard":"function hasWaveId(e: unknown): e is { waveId: string } {\n  return typeof (e as any)?.waveId === 'string' && (e as any).waveId.trim() !== ''\n}","tryCatchPattern":"const res = await fetch(url, opts)\nif (res.status === 400 && (await res.text()).includes('waveid is required')) {\n  // recover: re-acquire current wave id and rebuild the event\n}","preventionTips":["Bind waveId from live session state, never a hardcoded constant","Trim and check non-empty before sending","Add unit tests for event builders asserting waveId presence"],"tags":["http","validation","missing-field"],"backgroundTag":"missing-required-argument","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}