wavetermdev/waveterm · error

terminal input request failed: ${response.status} ${response

Error message

terminal input request failed: ${response.status} ${response.statusText}

What it means

sendTermInputEvent POSTs terminal keystroke/input events to the Tsunami server as JSON. If the response is not ok, the error reports the HTTP status so the caller knows the terminal input never reached the backend.

Source

Thrown at tsunami/frontend/src/vdom.tsx:310

}

function WaveMarkdown({ elem, model }: { elem: VDomElem; model: TsunamiModel }) {
    const props = useVDom(model, elem);
    return (
        <Markdown text={props?.text} style={props?.style} className={props?.className} scrollable={props?.scrollable} />
    );
}

async function sendTermInputEvent(event: VDomEvent) {
    const response = await fetch("/api/terminput", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify(event),
    });
    if (!response.ok) {
        throw new Error(`terminal input request failed: ${response.status} ${response.statusText}`);
    }
}

function WaveTerm({ elem, model }: { elem: VDomElem; model: TsunamiModel }) {
    const props = useVDom(model, elem);
    const hasOnData = props.onData != null;
    const onData = React.useCallback(
        (data: string | null, termsize: VDomTermSize | null) => {
            const terminput: VDomTermInputData = {};
            if (data != null) {
                terminput.data = data;
            }
            if (termsize != null) {
                terminput.termsize = termsize;
            }
            const event: VDomEvent = {
                waveid: elem.waveid,
                eventtype: "onData",

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check status: ECONNREFUSED/502 → server down, restart Tsunami; 400 → inspect the serialized event body; 404 → endpoint path drift.
  2. Verify the server URL/port used by vdom.tsx matches the running server.
  3. Add retry/queueing for input events so transient failures don't drop keystrokes; surface connection state in the UI.
  4. Confirm network/proxy allows the request to the local backend.

Example fix

// before
const response = await fetch(url, { method: "POST", body: JSON.stringify(event) });
if (!response.ok) throw new Error(`terminal input request failed: ${response.status} ${response.statusText}`);
// after
const response = await fetch(url, { method: "POST", body: JSON.stringify(event) });
if (!response.ok) {
  if (response.status >= 500) inputQueue.push(event); // retry later
  throw new Error(`terminal input request failed: ${response.status} ${response.statusText}`);
}
Defensive patterns

Strategy: retry

Validate before calling

async function serverReachable(url: string): Promise<boolean> {
  try {
    const res = await fetch(url, { method: "OPTIONS" });
    return res.status < 500;
  } catch {
    return false;
  }
}

Try / catch

try {
  await sendTermInputEvent(event);
} catch (e) {
  if (String(e.message).startsWith("terminal input request failed")) {
    console.warn("dropping/requeueing input, backend unreachable:", e.message);
    inputQueue.push(event); // or show disconnected indicator
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: POST of a term-input event returns non-2xx: server down/restarting while the terminal UI is still accepting keys, endpoint changed, oversized or malformed event body (400), or proxy dropping the request.

Common situations: Typing into a WaveTerm vdom block after the Tsunami backend crashed or during a restart, port/baseUrl misconfiguration, firewall or proxy interference with the local server.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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