windmill-labs/windmill · error

file path must refer to a file.

Error message

file path must refer to a file.

What it means

Thrown by the Windmill CLI's `resource push` command when the local path given to push does not point to a regular file on disk. After validating the remote path, the CLI calls stat(filePath) and requires the entry to be a file (isFile()); directories, sockets, symlinks-to-directories, or nonexistent paths fail (stat itself rejecting surfaces as ENOENT, but a directory hits this explicit error).

Source

Thrown at cli/src/commands/resource/resource.ts:177

        ...localResource,
        ...(wsSpecific !== undefined ? { ws_specific: wsSpecific } : {}),
      },
    });
  }
}

type PushOptions = GlobalOptions;
async function push(opts: PushOptions, filePath: string, remotePath: string) {
  const workspace = await resolveWorkspace(opts);
  await requireLogin(opts);

  if (!validatePath(remotePath)) {
    return;
  }

  const fstat = await stat(filePath);
  if (!fstat.isFile()) {
    throw new Error("file path must refer to a file.");
  }

  log.info(colors.bold.yellow("Pushing resource..."));

  await pushResource(
    workspace.workspaceId,
    remotePath,
    undefined,
    parseFromFile(filePath),
    filePath  // Pass the local file path for branch-specific inline content resolution
  );
  log.info(colors.bold.underline.green(`Resource ${remotePath} pushed`));
}

async function list(opts: GlobalOptions & { json?: boolean }) {
  if (opts.json) log.setSilent(true);
  const workspace = await resolveWorkspace(opts);
  await requireLogin(opts);

View on GitHub (pinned to e474e8803c)

Solutions

  1. Pass the actual resource YAML file path (e.g. ./myres.resource.yaml) instead of a directory
  2. If it's a symlink, point at or link the real file
  3. Verify with `ls -l <path>` / `test -f <path>` that the argument is a regular file before pushing

Example fix

// before
wmill resource push u/admin/myres ./resources/
// after
wmill resource push u/admin/myres ./resources/myres.resource.yaml
Defensive patterns

Strategy: validation

Validate before calling

import { statSync } from 'fs';

const st = statSync(localPath); // throws ENOENT early if missing
if (!st.isFile()) {
  throw new Error(`--path must be a .resource.yaml file, got: ${localPath}`);
}

Type guard

import { Stats, statSync } from 'fs';

async function isRegularFile(p: string): Promise<boolean> {
  try { return (await import('fs/promises')).default.stat(p).then(s => s.isFile()); } catch { return false; }
}
// sync variant:
function isFile(p: string): boolean { try { return statSync(p).isFile(); } catch { return false; } }

Try / catch

try {
  await wmill.resource.push(remotePath, localPath);
} catch (e) {
  if ((e as Error).message === 'file path must refer to a file.') {
    console.error(`${localPath} is a directory or not a regular file; pass the .resource.yaml file itself`);
  } else throw e;
}

Prevention

When it happens

Trigger: Running `wmill resource push <remote> <localPath>` where localPath is a directory (e.g. passing the containing folder instead of the `.resource.yaml` file), or a special/non-regular file. Note: a nonexistent path throws from stat with ENOENT before reaching this check.

Common situations: Passing a directory by mistake or relying on shell glob expansion that yielded a directory; pointing at a symlink that resolves to a directory; scripting that interpolates an empty or wrong variable so the path ends up as '.' or a folder; copy-pasting a folder path instead of the resource YAML file.

Related errors


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