louislam/dockge · error · Error
Terminal name must be a string.
Error message
Terminal name must be a string.
What it means
Thrown by the 'terminalInput' handler in TerminalSocketHandler when the terminalName argument is not a string. Terminal names are used to look up the active terminal map, so the handler validates the type first (then validates that cmd is a string too).
Source
Thrown at backend/agent-socket-handlers/terminal-socket-handler.ts:17
import { DockgeServer } from "../dockge-server";
import { callbackError, callbackResult, checkLogin, DockgeSocket, ValidationError } from "../util-server";
import { log } from "../log";
import { InteractiveTerminal, MainTerminal, Terminal } from "../terminal";
import { Stack } from "../stack";
import { AgentSocketHandler } from "../agent-socket-handler";
import { AgentSocket } from "../../common/agent-socket";
export class TerminalSocketHandler extends AgentSocketHandler {
create(socket : DockgeSocket, server : DockgeServer, agentSocket : AgentSocket) {
agentSocket.on("terminalInput", async (terminalName : unknown, cmd : unknown, callback) => {
try {
checkLogin(socket);
if (typeof(terminalName) !== "string") {
throw new Error("Terminal name must be a string.");
}
if (typeof(cmd) !== "string") {
throw new Error("Command must be a string.");
}
let terminal = Terminal.getTerminal(terminalName);
if (terminal instanceof InteractiveTerminal) {
//log.debug("terminalInput", "Terminal found, writing to terminal.");
terminal.write(cmd);
} else {
throw new Error("Terminal not found or it is not a Interactive Terminal.");
}
} catch (e) {
callbackError(e, callback);
}
});
View on GitHub (pinned to f809ae192b)
Solutions
- Pass the registered terminal name string (e.g. the combined terminal name) exactly as attached
- Only emit input after the terminal is attached and its name is known
- Validate typeof terminalName === 'string' before emitting
- If you hold a terminal object, send its name property, not the object
Example fix
// before
socket.emit("terminalInput", terminal, cmd, cb); // object
// after
socket.emit("terminalInput", terminalName, cmd, cb); // string name Defensive patterns
Strategy: type-guard
Validate before calling
function assertTerminalInput(terminalName: unknown, cmd: unknown): asserts terminalName is string {
if (typeof terminalName !== "string") throw new TypeError("terminalName must be a string");
if (typeof cmd !== "string") throw new TypeError("cmd must be a string");
} Type guard
const isTerminalName = (v: unknown): v is string => typeof v === "string" && v.length > 0;
Try / catch
socket.emit("terminalInput", terminalName, cmd, (res) => {
if (res && res.ok === false) console.warn("terminalInput rejected:", res.msg);
}); Prevention
- Emit input only after the terminal is attached and its name is registered
- Send the terminal's name string, not the xterm.js Terminal object
- Guard the keydown/data handler with a terminalName typeof check
When it happens
Trigger: socket.emit('terminalInput', terminalName, cmd) with terminalName undefined (terminal not attached yet), null, or an object (terminal instance passed instead of its name).
Common situations: Terminal component emits input before the connection/handshake assigns the terminal name; passing the xterm.js Terminal object instead of its registered name; automated input scripts with unset variables.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- Stack name and service name must be strings
- Invalid stackName or serviceName
- Compose YAML must be a string
- Compose ENV must be a string
- isAdd must be a boolean
AI-assisted analysis of louislam/dockge@f809ae192b (2026-08-31).
Data as JSON: /api/errors/9893cb8fbc804962.
Report an issue: GitHub.