windmill-labs/windmill · error · Error

${what} failed:\n${output}

Error message

${what} failed:\n${output}

What it means

Windmill resolves a python interpreter version from the requested constraint using uv's resolver. When no installable python version satisfies the requested constraint, it lists all known versions and throws this unsatisfiable-resolution error.

Source

Thrown at backend/windmill-api/src/apps_raw_bundler.ts:72

	for (const [p, content] of Object.entries(shared_ui ?? {})) {
		await write('ui/' + p.replace(/^\/+/, ''), content)
	}

	const manifest = path.join(dir, 'package.json')
	const hasPackageJson = Object.keys(files ?? {}).some((p) => target(p) === manifest)
	// Piped rather than inherited so the output can go in the error too, then
	// echoed either way — the job's log is where someone looks to see what the
	// build did.
	const spawn = (argv: string[]) => {
		const proc = Bun.spawnSync(argv, { cwd: dir, stdout: 'pipe', stderr: 'pipe' })
		const output = proc.stdout.toString() + proc.stderr.toString()
		console.log(output)
		return { ok: proc.exitCode === 0, output }
	}
	const run = (argv: string[], what: string) => {
		const { ok, output } = spawn(argv)
		if (!ok) {
			throw new Error(`${what} failed:\n${output}`)
		}
		return output
	}

	if (hasPackageJson) {
		// Installed here rather than left to the CLI so it can be --ignore-scripts:
		// the app's dependencies are compiled, never run, so a package's lifecycle
		// script has no business executing on the worker. The CLI skips its own
		// install once node_modules exists.
		run(['bun', 'install', '--ignore-scripts'], 'bun install')
	} else {
		// The CLI installs when node_modules is missing, and it shells out to npm,
		// which the slim images don't ship. An app with no manifest has nothing to
		// install, so hand it the empty directory it would have produced.
		await fs.mkdir(path.join(dir, 'node_modules'), { recursive: true })
	}

	const outDir = path.join(dir, 'dist')

View on GitHub (pinned to e474e8803c)

Solutions

  1. Correct the requested python version in the script settings to an existing release (e.g. 3.11, 3.12, 3.13)
  2. Read the 'All versions' list in the error and pick from it
  3. Update uv/python tooling on the worker so newer python versions are known
  4. Relax the constraint (e.g. '3.12' instead of '3.12.7') to allow any matching patch
  5. Check for stray characters in the version field (extra dot, whitespace, 'python' prefix)

Example fix

// before (script settings)
python_version = "3.14.0.1"
// after
python_version = "3.12"
Defensive patterns

Strategy: validation

Validate before calling

const KNOWN = ['3.8','3.9','3.10','3.11','3.12','3.13'];
function validatePythonVersion(v) {
  if (typeof v !== 'string') throw new Error('python version must be a string');
  const base = v.replace(/^python/i, '').split('.').slice(0,2).join('.');
  if (!/^\d+\.\d+$/.test(base)) throw new Error(`malformed python version: ${v}`);
  if (!KNOWN.includes(base)) throw new Error(`python ${base} not available; pick from ${KNOWN}`);
}

Type guard

const isPythonVersion = (v) => typeof v === 'string' && /^\d+\.\d+(\.\d+)?$/.test(v.trim());

Try / catch

try {
  await deployScript({ pythonVersion: '3.12' });
} catch (e) {
  if (/No solution found when resolving python/.test(e.message)) {
    const available = e.message.match(/All versions:[\s\S]*$/)?.[0];
    throw new Error(`Pick a python version from: ${available}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: A script/flow declares a python version requirement (e.g. python 3.99, or a narrow constraint) that matches none of the python versions available to the worker's resolver.

Common situations: Typo in the version string (3.13.0.1); requesting a version newer than any python known to the installed uv; pinning an exact patch version removed from the registry; workers with an outdated uv version catalogue.

Related errors


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