louislam/dockge · error · Error
Command must be a string.
Error message
Command must be a string.
What it means
Thrown inside the terminalInput socket handler (registered in create()) when the cmd argument sent by the client is not a string. The handler validates raw socket payloads because anything can be sent over the wire, so it explicitly checks typeof before writing to a terminal. It is a defensive input-validation error, not an internal failure.
Source
Thrown at backend/agent-socket-handlers/terminal-socket-handler.ts:21
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);
}
});
// Main Terminal
agentSocket.on("mainTerminal", async (terminalName : unknown, callback) => {
try {
checkLogin(socket);View on GitHub (pinned to f809ae192b)
Solutions
- Ensure the client passes the command as a plain string when emitting 'terminalInput' (String(cmd) if needed).
- Check client code for undefined/null command variables and handle the empty case before emitting.
- Log the payload on the client right before emit to confirm its type.
- Wrap the emit/callback in error handling and surface callbackError to the UI.
Example fix
// before
socket.emit("terminalInput", terminalName, cmd);
// after
if (typeof cmd === "string") {
socket.emit("terminalInput", terminalName, cmd);
} else {
console.error("terminalInput requires a string command, got:", typeof cmd);
} Defensive patterns
Strategy: type-guard
Validate before calling
function assertString(v) { if (typeof v !== "string") throw new TypeError("cmd must be a string, got " + typeof v); }
assertString(cmd); socket.emit("terminalInput", terminalName, cmd); Type guard
const isString = (v) => typeof v === "string";
Try / catch
socket.emit("terminalInput", terminalName, cmd, (res) => { if (res?.error) console.error("terminalInput failed:", res.error.message); }); Prevention
- Always pass commands as strings; serialize structured commands client-side before emitting.
- Lint for emit calls with non-literal arguments and add typeof assertions.
- Log payloads during development to catch undefined values early.
- Centralize socket emits in a typed wrapper that validates arguments.
When it happens
Trigger: Emitting the 'terminalInput' socket event with a command argument that is null, undefined, a number, an object, or an array instead of a string (e.g. terminalSocket.emit('terminalInput', name, 42)).
Common situations: Client-side state not yet initialized (undefined command), JSON payload deserialization surprises, UI sending keystroke objects instead of strings, or a refactored client API passing structured command objects.
Related errors
- Stack name must be a string.
- Service name must be a string.
- Shell must be a string.
- Command must be a number.
- Stack name and service name must be strings
AI-assisted analysis of louislam/dockge@f809ae192b (2026-08-31).
Data as JSON: /api/errors/c82acb50347afa75.
Report an issue: GitHub.