windmill-labs/windmill · error · Error

Cannot preview a script metadata file, point to the script c

Error message

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

What it means

`wmill script` preview/analysis commands operate on script CONTENT files; passing a script metadata file (.script.json or .script.yaml) is rejected because the metadata alone does not identify the code to preview.

Source

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

  filePath = toSyncRootRelativePath(filePath, cwdBeforeConfig);
  const remotePath = scriptPathToRemotePath(filePath);
  assertRemotePath(remotePath, argPath);

  // Same as push: a descriptor-less dbt project's content path is deliberately
  // absent, and 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 preview a script metadata file, point to the script content file instead (.py, .ts, .go, .sh)"
    );
  }

  const codebases = await listSyncCodebases(opts);
  const language = inferContentTypeFromFilePath(filePath, opts?.defaultTs);
  const content = await readScriptContent(filePath);
  const input = opts.data ? await resolve(opts.data) : {};

  // Read modules from the bundle folder if present. Same suffix and same
  // verbatim read as deploy: a dbt project lives in `__dbt/`, and parsing its
  // files as scripts would drop the `dbt_project.yml` the executor looks for.
  const isFolderLayout = isModuleEntryPoint(filePath);
  const isDbt = language === "dbt";
  const moduleFolderPath = isFolderLayout
    ? path.dirname(filePath)
    : filePath.substring(0, filePath.indexOf(".")) + getModuleFolderSuffix(language);
  const modules = await readModulesFromDisk(

View on GitHub (pinned to e474e8803c)

Solutions

  1. Point the command at the script content file: the sibling .py, .ts, .go or .sh
  2. Strip the .script.yaml/.script.json extension to derive the content file path
  3. Filter out *.script.json/*.script.yaml when scripting over a folder

Example fix

// before
wmill script analyze f/scripts/my_script.script.yaml
// after
wmill script analyze f/scripts/my_script.py
Defensive patterns

Strategy: validation

Validate before calling

if (/\.script\.(json|yaml)$/.test(filePath)) throw new Error(`Pass the content file instead of metadata: ${filePath.replace(/\.script\.(json|yaml)$/, '')}`);

Type guard

function isScriptMetadata(p: string): boolean { return p.endsWith('.script.json') || p.endsWith('.script.yaml'); }

Prevention

When it happens

Trigger: Running a preview-style command (around line 1876 of script.ts) with a path ending in .script.json or .script.yaml; the check happens after confirming the path is a file.

Common situations: Tab-completing or pasting the metadata file path instead of the sibling content file; scripting over a directory and iterating all files including metadata.

Related errors


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