windmill-labs/windmill · error · Error
Draft script "${path}" is missing content or language.
Error message
Draft script "${path}" is missing content or language. What it means
read_workspace_item / script-reading logic finds a draft script in the global draft store but the draft lacks a usable content string or a language. Rather than returning a half-written draft, the code throws so the model gets a clear signal the draft is incomplete. It guards the invariant that a readable script draft has both content and a ScriptLang.
Source
Thrown at frontend/src/lib/components/copilot/chat/global/core.ts:5123
function writeVariableDraft(args: WriteVariableArgs, ctx: WriteDraftCtx): Promise<string> {
// A variable's value is never interpolated, so "$var:<its own path>" as the value
// is always the model echoing the reference syntax back instead of a real value.
if (args.value === `$var:${args.path}`) {
throw new Error(
`"${args.value}" is not a valid value for variable "${args.path}" — it is a self-reference. Omit value to keep the current one.`
)
}
return writeDraft(VARIABLE_SPEC, 'variable', args.path, args, ctx, { override: args.override })
}
async function loadScriptForEdit(
path: string,
workspace: string
): Promise<{ content: string; language: ScriptLang; summary?: string }> {
const draft = await getGlobalDraft(workspace, 'script', path)
if (draft) {
if (typeof draft.value !== 'string' || !draft.language) {
throw new Error(`Draft script "${path}" is missing content or language.`)
}
return { content: draft.value, language: draft.language, summary: draft.summary }
}
const script = await ScriptService.getScriptByPath({ workspace, path })
return { content: script.content, language: script.language, summary: script.summary }
}
async function editScript(
args: { path: string; old_string: string; new_string: string; replace_all: boolean },
ctx: WriteDraftCtx
): Promise<string> {
const { path, old_string: oldString, new_string: newString, replace_all: replaceAll } = args
ctx.toolCallbacks.setToolStatus(ctx.toolId, { content: `Editing script "${path}"...` })
const base = await loadScriptForEdit(path, ctx.workspace)
const updated = findAndReplace(base.content, oldString, newString, replaceAll, 'script source')
return writeScriptDraft(
{View on GitHub (pinned to e474e8803c)
Solutions
- Delete the incomplete draft (delete draft for that script path) and re-run the read to fall back to the deployed script.
- Re-run write_script with both content and language to complete the draft, then read again.
- Read the deployed script via the normal script-by-path service call if you did not intend to work on a draft.
Example fix
// before (draft stored incomplete)
writeScript({ path: 'f/x', summary: 'todo' }) // no content/language
// after
writeScript({ path: 'f/x', content: 'export async function main() {}', language: 'python3' }) Defensive patterns
Strategy: type-guard
Validate before calling
const draft = await getGlobalDraft(workspace, 'script', path)
if (draft && (typeof draft.value !== 'string' || !draft.language)) {
await deleteGlobalDraft(workspace, 'script', path) // reset to deployed source
} Type guard
function isCompleteScriptDraft(d: unknown): d is { value: string; language: ScriptLang; summary?: string } {
const x = d as any
return !!x && typeof x.value === 'string' && typeof x.language === 'string' && !!x.language
} Try / catch
try {
return await readScript(path)
} catch (e) {
if (String(e.message).includes('missing content or language')) {
await deleteDraft('script', path)
return await ScriptService.getScriptByPath({ workspace, path })
}
throw e
} Prevention
- Always call write_script with both content and language in one call.
- Delete drafts left in partial state before reading.
- Treat draft existence as authoritative; complete drafts before read flows.
When it happens
Trigger: getGlobalDraft(workspace, 'script', path) returns a draft whose `value` is not a string or whose `language` is falsy — e.g. a draft created by a failed/partial write_script call or cleared content.
Common situations: A previous write_script tool call stored only metadata (language or summary) without content; a draft was created by template scaffolding that never filled the body; concurrent tool calls left the draft in a partial state.
Related errors
- Draft flow "${path}" has no value.
- Draft script "${moduleValue.path}" is missing content or lan
- path and hash_ are mutually exclusive
- path or hash_ must be provided
- preprocessor function is missing
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/de61dadab6aad41f.
Report an issue: GitHub.