TryGhost/Ghost · error · Error

Command failed with exit code ${exitCode}: ${command}\nSTDOU

Error message

Command failed with exit code ${exitCode}: ${command}\nSTDOUT: ${stdout}\nSTDERR: ${stderr}

What it means

MysqlManager runs a command inside the MySQL container via Docker exec, collects stdout/stderr streams, then inspects the exec for ExitCode. Any non-zero exit code produces this error embedding the command, stdout, and stderr. It's a thin wrapper surfacing the real failure of mysql/mysqladmin/sql inside the container (auth, syntax, missing DB, locked table).

Source

Thrown at e2e/helpers/environment/service-managers/mysql-manager.ts:256

        // Use Docker modem's demuxStream to separate stdout and stderr
        (container as ContainerWithModem).modem.demuxStream(stream, stdoutStream, stderrStream);

        // Wait for the stream to end
        await new Promise<void>((resolve, reject) => {
            stream.on('end', () => resolve());
            stream.on('error', reject);
        });

        // Get the exit code from exec inspection
        const execInfo = await exec.inspect();
        const exitCode = execInfo.ExitCode;

        const stdout = Buffer.concat(stdoutChunks).toString('utf8').trim();
        const stderr = Buffer.concat(stderrChunks).toString('utf8').trim();

        if (exitCode !== 0) {
            throw new Error(
                `Command failed with exit code ${exitCode}: ${command}\n` +
                `STDOUT: ${stdout}\n` +
                `STDERR: ${stderr}`
            );
        }

        return stdout;
    }
}

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Read STDERR in the message — the MySQL server error (access denied, unknown database, syntax) names the cause.
  2. Verify the credentials passed to exec match the container's MYSQL_ROOT_PASSWORD / user grants.
  3. Confirm the target database exists before running the command; create it if missing.
  4. Quote identifiers and validate SQL syntax before exec.

Example fix

// before: opaque exit-code failure

// after: validate DB exists and credentials before exec
const dbs = await mysqlManager.exec('mysql -uroot -p$PW -e "SHOW DATABASES"');
if (!dbs.includes(targetDb)) {
    await mysqlManager.exec(`mysql -uroot -p$PW -e "CREATE DATABASE \`${targetDb}\""`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

async function dbExists(m: MysqlManager, name: string): Promise<boolean> {
    const out = await m.exec(`mysql -uroot -p${PW} -e "SHOW DATABASES"`);
    return out.split('\n').some(l => l === name);
}

Try / catch

try {
    return await mysqlManager.exec(command);
} catch (e) {
    // message already embeds command/stdout/stderr — rethrow with cause for upstream context
    throw new Error(`mysql exec failed: ${(e as Error).message}`, {cause: e});
}

Prevention

When it happens

Trigger: Running mysql -e with wrong credentials (MYSQL_ROOT_PASSWORD mismatch). Querying a database that doesn't exist. SQL syntax error in the command. Container busy / table locked. The exec targeted a DB user lacking privileges.

Common situations: Wrong root password env between manager and container; database name typo; reserved keyword unquoted; flapping container where exec runs mid-restart.

Related errors


AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13). Data as JSON: /api/errors/d5421dc8e8aec1e2. Report an issue: GitHub.