windmill-labs/windmill · error · Error

bundle failed:\n${attempt.output}

Error message

bundle failed:\n${attempt.output}

What it means

Ruby inline-dependency jobs in Windmill are run through a patched bundler shim (windmill/inline). Requiring the stock 'bundler/inline' is blocked because it bypasses Windmill's Gemfile processing (source rewriting, credential handling), so this error is raised at resolve time.

Source

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

	const outDir = path.join(dir, 'dist')
	// Prefer the CLI the image installed: no npm reachability needed at deploy
	// time. It can predate `app bundle` (the images install it unpinned), and a
	// CLI without the command exits with cliffy's usage text before building
	// anything — so that specific failure, and only it, falls back to fetching
	// the one for this server's release. `wmill --version` isn't used to decide:
	// it reports npm's latest release as well as its own, and it reaches out to
	// npm to do so, which is the cost this branch exists to avoid.
	const installed = prefer_installed_cli ? Bun.which('wmill') : null
	let buildOutput: string | undefined
	if (installed) {
		const attempt = spawn([installed, 'app', 'bundle', dir, '--out', outDir])
		// Colours sit between the words cliffy prints, so match on the stripped text.
		const plain = attempt.output.replace(/\x1b\[[0-9;]*m/g, '')
		if (attempt.ok) {
			buildOutput = attempt.output
		} else if (!/Unknown command|Usage:\s+wmill app\b/.test(plain)) {
			throw new Error(`bundle failed:\n${attempt.output}`)
		}
	}
	if (buildOutput === undefined) {
		buildOutput = run([...cli_command, dir, '--out', outDir], 'bundle')
	}

	const read = async (name: string) => {
		try {
			return await fs.readFile(path.join(outDir, name), 'utf8')
		} catch {
			return ''
		}
	}
	const js = await read('bundle.js')
	const css = await read('bundle.css')
	if (js === '') {
		throw new Error('bundle produced no javascript:\n' + buildOutput)
	}

View on GitHub (pinned to e474e8803c)

Solutions

  1. Replace `require 'bundler/inline'` with `require 'windmill/inline'` — the Gemfile DSL is otherwise identical
  2. Keep the `gemfile(true) do ... end` block unchanged; only the require line changes
  3. Update internal templates/snippets that still reference bundler/inline

Example fix

// before
require 'bundler/inline'
// after
require 'windmill/inline'
Defensive patterns

Strategy: validation

Validate before calling

function validateRubyDeps(code) {
  if (/^\s*require\s*['"]bundler\/inline['"]/m.test(code)) {
    throw new Error("replace require 'bundler/inline' with require 'windmill/inline'");
  }
}

Try / catch

try {
  await runRubyScript(code);
} catch (e) {
  if (/require 'bundler\/inline'/.test(e.message)) {
    code = code.replace(/require\s*['"]bundler\/inline['"]/g, "require 'windmill/inline'");
    return runRubyScript(code);
  }
  throw e;
}

Prevention

When it happens

Trigger: A ruby script's top-of-file dependency block (or the script body) contains `require 'bundler/inline'` — detected by regex before execution.

Common situations: Scripts copied from generic bundler documentation or Stack Overflow that use the standard bundler/inline idiom; older Windmill scripts written before the windmill/inline shim existed.

Related errors


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