louislam/dockge · critical · Error

Fatal error: ${this.config.dataDir} is not a directory

Error message

Fatal error: ${this.config.dataDir} is not a directory

What it means

initDataDir ensures the configured data directory exists, then lstats it and requires it to be a directory; otherwise it throws 'Fatal error: <dataDir> is not a directory'. This guards against the dataDir path existing but being a regular file, symlink to a file, socket, etc., which would break all subsequent file writes (db-config.json, stacks dir, sqlite db).

Source

Thrown at backend/dockge-server.ts:554

    checkTimezone(timezone : string) {
        try {
            dayjs.utc("2013-11-18 11:55").tz(timezone).format();
        } catch (e) {
            throw new Error("Invalid timezone:" + timezone);
        }
    }

    /**
     * Initialize the data directory
     */
    initDataDir() {
        if (! fs.existsSync(this.config.dataDir)) {
            fs.mkdirSync(this.config.dataDir, { recursive: true });
        }

        // Check if a directory
        if (!fs.lstatSync(this.config.dataDir).isDirectory()) {
            throw new Error(`Fatal error: ${this.config.dataDir} is not a directory`);
        }

        // Create data/stacks directory
        if (!fs.existsSync(this.stacksDir)) {
            fs.mkdirSync(this.stacksDir, { recursive: true });
        }

        log.info("server", `Data Dir: ${this.config.dataDir}`);
    }

    /**
     * Init or reset JWT secret
     * @returns  JWT secret
     */
    async initJWTSecret() : Promise<Bean> {
        let jwtSecretBean = await R.findOne("setting", " `key` = ? ", [
            "jwtSecret",
        ]);

View on GitHub (pinned to f809ae192b)

Solutions

  1. Remove or rename the file at the configured dataDir path and create a directory there: mkdir -p /app/data
  2. Fix the --data-dir flag / DOCKGE_DATA_DIR env to point at a directory
  3. In Docker, mount a host directory (or named volume), not a single file: -v ./dockge-data:/app/data

Example fix

// before
docker run -v ./dockge.db:/app/data dockge/dockge
// after
docker run -v ./dockge-data:/app/data dockge/dockge
Defensive patterns

Strategy: validation

Validate before calling

const fs = require("fs");
const st = fs.existsSync(dataDir) ? fs.lstatSync(dataDir) : null;
if (st && !st.isDirectory()) { throw new Error(`${dataDir} exists but is not a directory; move it and create a directory`); }
if (!st) fs.mkdirSync(dataDir, { recursive: true });

Type guard

function isDirectoryPath(p) { try { return fs.lstatSync(p).isDirectory(); } catch { return false; } }

Try / catch

try { server.initDataDir(); } catch (e) { if (String(e.message).includes("is not a directory")) { console.error("Fix --data-dir / DOCKGE_DATA_DIR:", e.message); process.exit(1); } throw e; }

Prevention

When it happens

Trigger: --data-dir / DOCKGE_DATA_DIR (or config stack dir) points at a regular file; a file was accidentally created at the path (e.g. docker run mounted a single file where a dir was expected); a broken/symlink loop causing lstat to throw.

Common situations: Docker: '-v ./data.txt:/app/data' mounting a file as the data dir; typo in path where an existing filename matches; restore from backup extracted a file at the dataDir path.

Related errors


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