windmill-labs/windmill · error

Pipeline node content must declare the pipeline annotation o

Error message

Pipeline node content must declare the pipeline annotation on its own comment line (`// pipeline`, or `-- pipeline` for SQL / `# pipeline` for Python).

What it means

A Windmill pipeline node is defined by the `// pipeline` annotation comment in its script content (with per-language variants `-- pipeline` for SQL and `# pipeline` for Python). assertPipelineAnnotation parses the content and throws this error when the annotation is absent, so a staged draft can't silently become a non-member script.

Source

Thrown at frontend/src/lib/components/assets/AssetGraph/pipelineAiHelpers.ts:160

	function assertInFolder(path: string) {
		const folder = folderName()
		if (folder && !path.startsWith(`f/${folder}/`)) {
			// Name the corrected path rather than only the required prefix: the model
			// otherwise re-sends variants of the same wrong path. A path that is the
			// folder itself has no node leaf to reuse.
			const leaf = path.split('/').filter(Boolean).pop()
			const node = !leaf || leaf === folder ? '<node_name>' : leaf
			throw new Error(
				`Pipeline nodes must be in the open folder — use 'f/${folder}/${node}' (got '${path}').`
			)
		}
	}

	// A pipeline node IS its `// pipeline` annotation (it's what makes the deployed
	// script a pipeline member). Reject content that lacks it so a staged draft
	// isn't a non-member script the model can't see is broken until deploy.
	function assertPipelineAnnotation(content: string) {
		if (!parsePipelineAnnotations(content).inPipeline) {
			throw new Error(
				`Pipeline node content must declare the pipeline annotation on its own comment line ` +
					`(\`// pipeline\`, or \`-- pipeline\` for SQL / \`# pipeline\` for Python).`
			)
		}
	}

	function buildContext(): PipelineContext {
		const graph = deps.getResolvedGraph()
		const drafts = deps.getDrafts()
		const nodes: PipelineNodeSummary[] = graph.runnables
			.filter((r) => r.usage_kind === 'script')
			.map((r) => {
				const draft = drafts.get(r.path)
				const writes = graph.edges
					.filter(
						(e) =>
							e.runnable_kind === 'script' &&

View on GitHub (pinned to e474e8803c)

Solutions

  1. Add the annotation as its own first comment line matching the language: `// pipeline` (JS/TS), `-- pipeline` (SQL), `# pipeline` (Python)
  2. Ensure the annotation is a standalone line — not trailing code or inside a block comment/string
  3. Verify the comment token matches the script's language attribute
  4. Re-run the write/stage call after adding the annotation

Example fix

// before (JS/TS node)
export async function main() { ... }
// after
// pipeline
export async function main() { ... }
Defensive patterns

Strategy: validation

Validate before calling

const ANNOTATION = /(^|\n)\s*(\/\/|--|#) pipeline\s*(\n|$)/
function hasPipelineAnnotation(content: string): boolean {
  return ANNOTATION.test(content)
}
if (!hasPipelineAnnotation(draftContent)) {
  draftContent = '// pipeline\n' + draftContent // or '# pipeline' for Python, '-- pipeline' for SQL
}

Type guard

function declaresPipeline(content: string): boolean {
  return parsePipelineAnnotations(content).inPipeline
}

Try / catch

try {
  await stageNode(path, content)
} catch (e) {
  if (e instanceof Error && e.message.includes('pipeline annotation')) {
    return stageNode(path, prependAnnotation(content, language))
  }
  throw e
}

Prevention

When it happens

Trigger: Writing or staging pipeline node content via the AI helpers where the content string lacks a standalone comment line `// pipeline` (or the SQL/Python equivalents) — e.g. the model generated a plain script body, the annotation was stripped by a formatter, or it was embedded inside another statement/string rather than on its own comment line.

Common situations: Model-generated content omitting the header comment; a code formatter removing or reflowing the comment; writing `#pipeline` (no space), inline trailing annotation like `foo() // pipeline` on a code line, or using the wrong comment token for the script language; content written with a block comment instead of a line comment.

Related errors


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