windmill-labs/windmill · error

Path is not a directory

Error message

Path is not a directory

What it means

The CLI's config-directory resolver (`throwIfNotDirectory`, called from `ensureDir`) stats a candidate configuration path and throws if the path exists but is a file (or symlink to a file) rather than a directory. This guards directory creation/setup of the Windmill config location (e.g. `~/.config/windmill`). It means the expected config directory path is occupied by something that is not a directory.

Source

Thrown at cli/windmill-utils-internal/src/config/config.ts:25

export const WINDMILL_ACTIVE_INSTANCE_FILE = "activeInstance";

function getEnv(key: string): string | undefined {
  return process.env[key];
}

function getOS(): "linux" | "darwin" | "windows" | null {
  const platform = process.platform;
  switch (platform) {
    case "linux": return "linux";
    case "darwin": return "darwin";
    case "win32": return "windows";
    default: return null;
  }
}

function throwIfNotDirectory(fileInfo: import("node:fs").Stats): void {
  if (!fileInfo.isDirectory()) {
    throw new Error("Path is not a directory");
  }
}

function config_dir(): string | null {
  const os = getOS();
  switch (os) {
    case "linux": {
      const xdg = getEnv("XDG_CONFIG_HOME");
      if (xdg) return xdg;

      const home = getEnv("HOME");
      if (home) return `${home}/.config`;
      break;
    }

    case "darwin": {
      const home = getEnv("HOME");
      if (home) return `${home}/Library/Preferences`;

View on GitHub (pinned to e474e8803c)

Solutions

  1. Inspect the path: `ls -la` / `stat` the reported config location and check what is there
  2. If it is a stale/unused file, delete or rename it (`mv file file.bak`) and retry
  3. If it holds needed config, move the file contents into a directory of that name
  4. Fix the env var / flag so it points at a directory, not a file
  5. Check for a bad symlink (`readlink`) and repoint it

Example fix

// before
WINDMILL_CONFIG_DIR=~/.windmill.yaml wmill sync pull  // path is a file -> throws

// after
mkdir -p ~/.windmill && mv ~/.windmill.yaml ~/.windmill/config.yaml
WINDMILL_CONFIG_DIR=~/.windmill wmill sync pull
Defensive patterns

Strategy: validation

Validate before calling

import { statSync } from 'node:fs';
function assertConfigDirWritable(p: string): void {
  const st = statSync(p);
  if (!st.isDirectory()) {
    throw new Error(`${p} exists and is not a directory; move it aside first`);
  }
}

Type guard

function isDirectory(p: string): boolean {
  try { return statSync(p).isDirectory(); } catch { return false; }
}

Try / catch

try {
  ensureDir(configPath);
} catch (e) {
  if ((e as Error).message === 'Path is not a directory') {
    console.error(`${configPath} is a file — rename it and retry`);
    process.exit(1);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `ensureDir` on a config path where a regular file already exists at that exact path; a stale file named like the config directory (e.g. `$WINDMILL_CONFIG_DIR` or the OS config dir resolves to a file); a symlink pointing to a file.

Common situations: Users set an env var pointing the CLI at a file (accidentally passing a config *file* path instead of a directory); Docker volume mounts that created a file where a directory was expected; interrupted tooling left a stray file named `windmill` in `~/.config`.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/a1f97bc62e46b077. Report an issue: GitHub.