{"record":{"id":"de61dadab6aad41f","repo":"windmill-labs/windmill","slug":"draft-script-path-is-missing-content-or-langu","errorCode":null,"errorMessage":"Draft script \"${path}\" is missing content or language.","messagePattern":"Draft script \"(.+?)\" is missing content or language\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/chat/global/core.ts","lineNumber":5123,"sourceCode":"function writeVariableDraft(args: WriteVariableArgs, ctx: WriteDraftCtx): Promise<string> {\n\t// A variable's value is never interpolated, so \"$var:<its own path>\" as the value\n\t// is always the model echoing the reference syntax back instead of a real value.\n\tif (args.value === `$var:${args.path}`) {\n\t\tthrow new Error(\n\t\t\t`\"${args.value}\" is not a valid value for variable \"${args.path}\" — it is a self-reference. Omit value to keep the current one.`\n\t\t)\n\t}\n\treturn writeDraft(VARIABLE_SPEC, 'variable', args.path, args, ctx, { override: args.override })\n}\n\nasync function loadScriptForEdit(\n\tpath: string,\n\tworkspace: string\n): Promise<{ content: string; language: ScriptLang; summary?: string }> {\n\tconst draft = await getGlobalDraft(workspace, 'script', path)\n\tif (draft) {\n\t\tif (typeof draft.value !== 'string' || !draft.language) {\n\t\t\tthrow new Error(`Draft script \"${path}\" is missing content or language.`)\n\t\t}\n\t\treturn { content: draft.value, language: draft.language, summary: draft.summary }\n\t}\n\tconst script = await ScriptService.getScriptByPath({ workspace, path })\n\treturn { content: script.content, language: script.language, summary: script.summary }\n}\n\nasync function editScript(\n\targs: { path: string; old_string: string; new_string: string; replace_all: boolean },\n\tctx: WriteDraftCtx\n): Promise<string> {\n\tconst { path, old_string: oldString, new_string: newString, replace_all: replaceAll } = args\n\tctx.toolCallbacks.setToolStatus(ctx.toolId, { content: `Editing script \"${path}\"...` })\n\n\tconst base = await loadScriptForEdit(path, ctx.workspace)\n\tconst updated = findAndReplace(base.content, oldString, newString, replaceAll, 'script source')\n\treturn writeScriptDraft(\n\t\t{","sourceCodeStart":5105,"sourceCodeEnd":5141,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/chat/global/core.ts#L5105-L5141","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (draft stored incomplete)\nwriteScript({ path: 'f/x', summary: 'todo' }) // no content/language\n// after\nwriteScript({ path: 'f/x', content: 'export async function main() {}', language: 'python3' })","handlingStrategy":"type-guard","validationCode":"const draft = await getGlobalDraft(workspace, 'script', path)\nif (draft && (typeof draft.value !== 'string' || !draft.language)) {\n  await deleteGlobalDraft(workspace, 'script', path) // reset to deployed source\n}","typeGuard":"function isCompleteScriptDraft(d: unknown): d is { value: string; language: ScriptLang; summary?: string } {\n  const x = d as any\n  return !!x && typeof x.value === 'string' && typeof x.language === 'string' && !!x.language\n}","tryCatchPattern":"try {\n  return await readScript(path)\n} catch (e) {\n  if (String(e.message).includes('missing content or language')) {\n    await deleteDraft('script', path)\n    return await ScriptService.getScriptByPath({ workspace, path })\n  }\n  throw e\n}","preventionTips":["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."],"tags":["draft-state","scripts","ai-tooling"],"backgroundTag":"incomplete-draft-state","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}