louislam/dockge · error · ValidationError

dockerRunCommand must be a string

Error message

dockerRunCommand must be a string

What it means

The 'composerize' socket event converts a docker run command into docker-compose YAML. The dockerRunCommand argument is typed unknown, so the handler first performs a strict typeof check and throws a ValidationError if it is not a string. This guarantees composerize() only ever receives string input.

Source

Thrown at backend/socket-handlers/main-socket-handler.ts:329

        // Disconnect all other socket clients of the user
        socket.on("disconnectOtherSocketClients", async () => {
            try {
                checkLogin(socket);
                server.disconnectAllSocketClients(socket.userID, socket.id);
            } catch (e) {
                if (e instanceof Error) {
                    log.warn("disconnectOtherSocketClients", e.message);
                }
            }
        });

        // composerize
        socket.on("composerize", async (dockerRunCommand : unknown, callback) => {
            try {
                checkLogin(socket);

                if (typeof(dockerRunCommand) !== "string") {
                    throw new ValidationError("dockerRunCommand must be a string");
                }

                // Option: 'latest' | 'v2x' | 'v3x'
                let composeTemplate = composerize(dockerRunCommand, "", "latest");

                // Remove the first line "name: <your project name>"
                composeTemplate = composeTemplate.split("\n").slice(1).join("\n");

                callback({
                    ok: true,
                    composeTemplate,
                });
            } catch (e) {
                callbackError(e, callback);
            }
        });
    }

View on GitHub (pinned to f809ae192b)

Solutions

  1. Pass the docker run command as a single string, e.g. 'docker run -d -p 8080:80 nginx'.
  2. Join array tokens with spaces before emitting: args.join(' ').
  3. Coerce/guard the value: if (typeof cmd === 'string') emit(...).

Example fix

// before
socket.emit('composerize', ['-d', '-p', '8080:80', 'nginx'], cb);
// after
socket.emit('composerize', 'docker run -d -p 8080:80 nginx', cb);
Defensive patterns

Strategy: type-guard

Validate before calling

function isDockerRunCommand(v) {
    return typeof v === 'string' && v.trim().startsWith('docker run');
}

Type guard

function isString(v) { return typeof v === 'string'; }

Try / catch

try {
    socket.emit('composerize', cmd, (res) => {
        if (!res.ok) throw new TypeError('dockerRunCommand must be a string');
    });
} catch (e) {
    if (e instanceof TypeError) showInputError(e.message);
}

Prevention

When it happens

Trigger: Emitting 'composerize' with a non-string first argument: null, undefined, an object like { cmd: '...' }, an array of args, or a number.

Common situations: Frontend binding an unset input model (undefined) to the event; scripts passing an array of CLI tokens instead of one joined string; JSON payloads where the value arrived as an object.

Understand the failure class

Background: "Wrong argument type", "must be a string", "expected Array or Prism::Scope": TypeError and ArgumentError when a library receives a value of the wrong type — this error's family across 28 libraries.

Related errors


AI-assisted analysis of louislam/dockge@f809ae192b (2026-08-31). Data as JSON: /api/errors/e1f9f1d95564d08c. Report an issue: GitHub.