windmill-labs/windmill · error · Error
path and hash_ are mutually exclusive
Error message
path and hash_ are mutually exclusive
What it means
runScriptAsync accepts either a script path or a deployed script hash to identify the script to run, but not both. Passing both arguments throws this error immediately, before any API call, because the two identifiers are alternative selectors for the same script.
Source
Thrown at backend/windmill-runtime-nativets/src/windmill-client.js:9975
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${getEnv("WM_TOKEN")}`,
},
body: JSON.stringify({ args }),
}
);
let jobId = await req.text();
console.log(`Started task ${f.name} as job ${jobId}`);
let r = await waitJob(jobId);
console.log(`Task ${f.name} (${jobId}) completed`);
return r;
};
}
async function runScriptAsync(path, hash_, args, scheduledInSeconds = null) {
!clientSet && setClient();
if (path && hash_) {
throw new Error("path and hash_ are mutually exclusive");
}
args = args || {};
const params = {};
if (scheduledInSeconds) {
params["scheduled_in_secs"] = scheduledInSeconds;
}
let parentJobId = getEnv("WM_JOB_ID");
if (parentJobId !== void 0) {
params["parent_job"] = parentJobId;
}
let rootJobId = getEnv("WM_ROOT_FLOW_JOB_ID");
if (rootJobId != void 0 && rootJobId != "") {
params["root_job"] = rootJobId;
}
let endpoint;
if (path) {
endpoint = `/w/${getWorkspace()}/jobs/run/p/${path}`;
} else if (hash_) {View on GitHub (pinned to e474e8803c)
Solutions
- Pass only one identifier: set the other argument to null/undefined.
- Prefer the path for readability, or the hash to pin an exact deployed version.
- Add a validation/coalescing step upstream so only one of the two is ever forwarded.
Example fix
// before await runScriptAsync(cfg.path, cfg.hash, args); // throws when both set // after await runScriptAsync(cfg.path ?? null, cfg.hash ?? null, args); // still validate one is set // or explicitly: await runScriptAsync(cfg.hash ? null : cfg.path, cfg.hash, args);
Defensive patterns
Strategy: validation
Validate before calling
function runScriptChecked(path, hash_, args) {
if (path && hash_) throw new TypeError('path and hash_ are mutually exclusive');
if (!path && !hash_) throw new TypeError('path or hash_ must be provided');
return runScriptAsync(path ?? null, hash_ ?? null, args);
} Prevention
- Normalize identifiers at the config boundary: keep a discriminated { path } | { hash } object.
- Pass null (not '') for the unused argument so truthiness checks behave.
- Write a thin wrapper that enforces the constraint once instead of at every call site.
When it happens
Trigger: Calling runScriptAsync(path, hash_, args) with truthy values for both `path` and `hash_` — e.g. copying an example that sets both, or forwarding optional parameters without nulling the unused one.
Common situations: Dynamic code that computes both a path and a hash from config and doesn't clear the other; wrappers around runScriptAsync that pass through raw config objects.
Related errors
- path or hash_ must be provided
- ApiError with mapped HTTP status message (e.g. "Not Found",
- Generic Error: status: ${errorStatus}; status text: ${errorS
- preprocessor function is missing
- ${main_name} function is missing
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/61cb34fe902d3339.
Report an issue: GitHub.