windmill-labs/windmill · error · Error

Cannot push a script metadata file, point to the script cont

Error message

Cannot push a script metadata file, point to the script content file instead (.py, .ts, .go|.sh)

What it means

The wmill script push command expects the path to a script CONTENT file (.py, .ts, .go, .sh, etc.). Passing a script metadata file (.script.json or .script.yaml) — which only holds settings, not code — is rejected upfront with this error, guiding the user to the correct file.

Source

Thrown at cli/src/commands/script/script.ts:191

    return;
  }

  // A dbt project's descriptor is optional, so the one content path a
  // descriptor-less project has is deliberately not on disk. The project beside
  // it is what says the script is real.
  const absentDescriptor = await stat(filePath).then(
    () => false,
    (e) => isMissingDbtDescriptor(filePath, e)
  );
  if (!absentDescriptor) {
    const fstat = await stat(filePath);
    if (!fstat.isFile()) {
      throw new Error("file path must refer to a file.");
    }
  }

  if (filePath.endsWith(".script.json") || filePath.endsWith(".script.yaml")) {
    throw Error(
      "Cannot push a script metadata file, point to the script content file instead (.py, .ts, .go|.sh)"
    );
  }

  if (isFileResource(filePath) || isFilesetResource(filePath)) {
    throw Error(
      "Cannot push a file/fileset resource content file as a script, push its .resource.yaml with 'wmill resource push' instead"
    );
  }

  await requireLogin(opts);

  // Warn about metadata state before pushing
  try {
    const content = await readScriptContent(filePath);
    const remotePath = removeExtensionToPath(filePath).replaceAll(SEP, "/");
    const contentHash = await computePushMetadataHash(filePath, content);
    const conf = await readLockfile();

View on GitHub (pinned to e474e8803c)

Solutions

  1. Point the push at the content file instead: `wmill script push path/to/script.py --path u/user/my_script` (the metadata lives alongside as .script.json and is applied automatically).
  2. If pushing a whole directory of scripts, use `wmill script sync` or filter out *.script.json/*.script.yaml from your push script.
  3. If you only have the metadata file, recover/regenerate the content file — the metadata does not contain the code.

Example fix

# before
wmill script push u/user/my_script.script.json

# after
wmill script push u/user/my_script.ts --path u/user/my_script --summary "..."
Defensive patterns

Strategy: validation

Validate before calling

const CONTENT_RE = /\.(py|ts|go|sh|sql|billing|php|rs|nu|jsx|tsx|flow|yaml\.flow)$/;
if (filePath.endsWith('.script.json') || filePath.endsWith('.script.yaml')) {
  filePath = filePath.replace(/\.script\.(json|yaml)$/, ''); // derive content file
}
if (!CONTENT_RE.test(filePath)) throw new Error(`not a script content file: ${filePath}`);

Prevention

When it happens

Trigger: Running `wmill script push path/to/script.script.json` or `... .script.yaml` — detected in push() by the filePath.endsWith checks before any login/API work.

Common situations: Syncing a repo and pushing every file including metadata files; confusing the metadata file (used by `wmill script` sync/to-json tooling) with the code file; tab-completion picking the .script.json instead of the .py/.ts sibling.

Related errors


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