windmill-labs/windmill · error
local script ${path} has no content/language
Error message
local script ${path} has no content/language What it means
Before launching a local (workspace-resident) pipeline script during a cascade run, makeLaunch checks that the script has both `content` and `language`. It throws this error when a locally resolved script came back from the workspace without usable body or language, since runScriptPreview requires both fields.
Source
Thrown at frontend/src/lib/components/assets/AssetGraph/cascadeRun.ts:86
tempScriptRefs?: Record<string, string>
// Extra run args for a specific node (e.g. the uploaded S3Object bound to a
// `data_upload` cascade root). Merged over `_wmill_skip_asset_dispatch`; all
// other nodes run with empty inputs as before.
argsFor?: (path: string) => Record<string, any> | undefined
onLaunched?: (path: string, jobId: string) => void
}): (path: string) => Promise<string> {
return async function launch(path: string): Promise<string> {
const local = opts.resolveLocal?.(path)
// Caller args (e.g. the run form for the cascade root) must NOT be able to
// re-enable backend asset dispatch while the client orchestrates the closure
// — that would double-run downstream / run deployed subscribers. Drop any
// `_wmill_skip_asset_dispatch` a caller supplied, and always spread it LAST.
const { _wmill_skip_asset_dispatch: _reserved, ...extra } = opts.argsFor?.(path) ?? {}
void _reserved
let jobId: string
if (local) {
if (!local.content || !local.language) {
throw new Error(`local script ${path} has no content/language`)
}
jobId = await JobService.runScriptPreview({
workspace: opts.workspace,
requestBody: {
content: local.content,
language: local.language,
path,
args: { ...extra, _wmill_skip_asset_dispatch: true },
...(local.tag ? { tag: local.tag } : {}),
...(opts.tempScriptRefs ? { temp_script_refs: opts.tempScriptRefs } : {})
}
})
} else {
jobId = await JobService.runScriptByPath({
workspace: opts.workspace,
path,
requestBody: { ...extra, _wmill_skip_asset_dispatch: true }
})View on GitHub (pinned to e474e8803c)
Solutions
- Open the script at that path in the Windmill hub and re-save/deploy it with real content and a language
- Re-fetch the script with content included (ensure the resolver requests full script data, not metadata-only)
- If the path is wrong, correct the asset/dependency reference to point at the deployed script
- For generated drafts, populate `content` and `language` before dispatching the cascade run
Example fix
// before
const local = await resolveLocal(path) // { path } only — no content
await launch(path)
// after
const local = await getScriptByPath({ workspace, path }) // full content + language
if (!local?.content || !local?.language) throw new Error(`script ${path} missing on workspace`)
await launch(path) Defensive patterns
Strategy: validation
Validate before calling
const local = await resolveLocal(path)
if (!local?.content?.trim() || !local?.language) {
throw new Error(`local script ${path} is empty or has no language; redeploy it before running the cascade`)
} Type guard
function isRunnableScript(s: { content?: string | null; language?: string | null } | null): s is { content: string; language: string } {
return !!s && typeof s.content === 'string' && s.content.trim().length > 0 && typeof s.language === 'string'
} Try / catch
try {
await launch(path)
} catch (e) {
if (e instanceof Error && e.message.includes('has no content/language')) {
const fresh = await getScriptByPath({ workspace, path }) // re-fetch full content
if (!fresh?.content || !fresh?.language) throw new Error(`script ${path} missing on workspace; fix the asset reference`)
return launch(path, fresh)
}
throw e
} Prevention
- Always fetch scripts with content included, never metadata-only responses
- Verify referenced script paths exist and are fully deployed before cascade runs
- Don't point asset graph nodes at empty drafts
- Re-save scripts after imports/migrations that could strip content
When it happens
Trigger: `resolveLocal(path)` returned a script object with empty/undefined `content` or `language` — e.g. the script exists but its deployment metadata was fetched instead of full content, the script is a draft/empty stub, or the resolver silently returned a skeleton object for a missing path.
Common situations: Script deployed from a flow without content; script fetched with `include_content` off or a partial get; asset graph pointing at a node whose underlying script was deleted or emptied; language not persisted for very old scripts or manually inserted DB rows.
Related errors
- Pipeline node content must declare the pipeline annotation o
- Field properties should be an object
- `oneOf` needs to be an array
- oneOf variant definition should have a `title` field
- oneOf variant definition `title` field should be a string
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/a64b8cb5f8fb2e55.
Report an issue: GitHub.