windmill-labs/windmill · error

no first step found

Error message

no first step found

What it means

getFirstStepSchema reads the input schema from the flow's first module. It throws when the flow has no modules at all (flow.value.modules[0] is undefined) or when the flowState map has no entry for the first module's id — meaning the first step's state was never initialized.

Source

Thrown at frontend/src/lib/components/flows/flowStore.svelte.ts:50

				v.input_transforms[key] = {
					type: 'javascript',
					expr: `flow_input.${key}`
				}
			})
			return
		}
		sendUserToast('Only scripts can be used as a input schema', true)
		return
	}
	sendUserToast('No first step found', true)
	return
}

export async function getFirstStepSchema(flowState: FlowState, flow: OpenFlow) {
	const firstModuleId = flow.value.modules[0]?.id

	if (!firstModuleId || !flowState[firstModuleId]) {
		throw new Error('no first step found')
	}

	const schema = $state.snapshot(flowState[firstModuleId].schema)
	const v = flow.value.modules[0].value

	if (v.type !== 'rawscript' && v.type !== 'script') {
		throw new Error('only scripts can be used as a input schema')
	}

	const simplifiedModule = {
		id: flow.value.modules[0].id,
		summary: flow.value.modules[0].summary,
		value: {
			type: flow.value.modules[0].value.type,
			...('path' in flow.value.modules[0].value ? { path: flow.value.modules[0].value.path } : {}),
			...('language' in flow.value.modules[0].value
				? { language: flow.value.modules[0].value.language }
				: {})

View on GitHub (pinned to e474e8803c)

Solutions

  1. Ensure the flow has at least one module before calling (flow.value.modules.length > 0).
  2. Initialize flowState entries for every module id before invoking; await flow state initialization before schema reads.
  3. Guard the call site: skip schema extraction when the first module is missing from state.

Example fix

// before
const schema = await getFirstStepSchema(flowState, flow)
// after
const firstId = flow.value.modules[0]?.id
if (!firstId || !flowState[firstId]) return null
const schema = await getFirstStepSchema(flowState, flow)
Defensive patterns

Strategy: type-guard

Validate before calling

const firstModuleId = flow.value.modules[0]?.id
const ready = Boolean(firstModuleId && flowState[firstModuleId])

Type guard

function hasFirstStepState(fs: FlowState, flow: OpenFlow): fs is FlowState & Record<string, { schema: unknown }> {
  const id = flow.value.modules[0]?.id
  return !!id && !!fs[id]
}

Try / catch

try {
  const schema = await getFirstStepSchema(flowState, flow)
} catch (e) {
  if (e.message === 'no first step found') return null
  throw e
}

Prevention

When it happens

Trigger: Calling getFirstStepSchema with an empty flow (modules array empty) or with a FlowState object missing the key for flow.value.modules[0].id (e.g., state built from a different or partially-loaded flow).

Common situations: Previewing input schema for a brand-new empty flow; flow state and flow definition out of sync after a partial load or race during flow initialization; passing a flowState snapshot from another flow version.

Related errors


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