wavetermdev/waveterm · error

terminput is required

Error message

terminput is required

What it means

Besides waveId, the event must contain a TermInput payload — that is what this endpoint dispatches via h.Client.Root.Event. If event.TermInput is nil after JSON parsing, the handler returns 400 'terminput is required'.

Source

Thrown at tsunami/engine/serverhandlers.go:428

	}

	body, err := io.ReadAll(r.Body)
	if err != nil {
		http.Error(w, fmt.Sprintf("failed to read request body: %v", err), http.StatusBadRequest)
		return
	}

	var event vdom.VDomEvent
	if err := json.Unmarshal(body, &event); err != nil {
		http.Error(w, fmt.Sprintf("failed to parse JSON: %v", err), http.StatusBadRequest)
		return
	}
	if strings.TrimSpace(event.WaveId) == "" {
		http.Error(w, "waveid is required", http.StatusBadRequest)
		return
	}
	if event.TermInput == nil {
		http.Error(w, "terminput is required", http.StatusBadRequest)
		return
	}

	h.renderLock.Lock()
	h.Client.Root.Event(event, h.Client.GlobalEventHandler)
	h.renderLock.Unlock()

	w.WriteHeader(http.StatusNoContent)
}

func (h *httpHandlers) handleDynContent(w http.ResponseWriter, r *http.Request) {
	defer func() {
		panicErr := util.PanicHandler("handleDynContent", recover())
		if panicErr != nil {
			http.Error(w, fmt.Sprintf("internal server error: %v", panicErr), http.StatusInternalServerError)
		}
	}()

View on GitHub (pinned to a4447c1563)

Solutions

  1. Include a termInput object in the JSON body (e.g. {"inputData":"..."})
  2. Confirm you are calling the correct endpoint for your event type
  3. Inspect VDomEvent's TermInput struct shape and fill required sub-fields
  4. If building events in Go, ensure the *TermInput pointer is non-nil before marshaling

Example fix

// before
{"waveId":"wave-1234"}
// after
{"waveId":"wave-1234","termInput":{"inputData":"ls\n"}}
Defensive patterns

Strategy: validation

Validate before calling

if (event.termInput == null) {
  throw new Error('terminput is required: this endpoint only accepts terminal-input events')
}

Type guard

function hasTermInput(e: unknown): e is { termInput: { inputData: string } } {
  return (e as any)?.termInput != null && typeof (e as any).termInput === 'object'
}

Try / catch

const res = await fetch(url, opts)
if (res.status === 400 && (await res.text()).includes('terminput is required')) {
  // route the event to the correct endpoint instead
}

Prevention

When it happens

Trigger: POSTing an event with a valid waveId but no termInput object, termInput explicitly null, or posting an event type meant for a different endpoint (e.g. a vdom event that is not terminal input).

Common situations: Copy-pasted payload templates where the termInput block was deleted; sending UI events (clicks, keys from other blocks) to the term-input endpoint by mistake; serializers omitting nil fields and the field never being set.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/bcb8524e1422b9f0. Report an issue: GitHub.