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
- Replace `require 'bundler/inline'` with `require 'windmill/inline'` — the Gemfile DSL is otherwise identical
- Keep the `gemfile(true) do ... end` block unchanged; only the require line changes
- 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
- Always use windmill/inline in Windmill ruby scripts
- Lint templates/snippets for the old require line
- Keep team ruby starter templates updated
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
- bundle produced no javascript:\n${buildOutput}
- no policy could be derived for runnable(s) ${malformed.join(
- result.substring(__ERR_PREFIX.length)
- `require 'windmill/inline'` is not detected - please add `re
- could not read the run of job ${id}: ${res.status} ${await r
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/39bbb757b4dd8fcc.
Report an issue: GitHub.