{"record":{"id":"ab5c001cbc3ff5be","repo":"windmill-labs/windmill","slug":"no-policy-could-be-derived-for-runnable-s-malfo","errorCode":null,"errorMessage":"no policy could be derived for runnable(s) ${malformed.join(', ')}: each must be an object with a `type` of \"inline\" (with `inlineScript.content`) or \"path\" (with `path` and a `runType` of ${RUN_TYPES.join(', ')})","messagePattern":"no policy could be derived for runnable\\(s\\) (.+?): each must be an object with a `type` of \"inline\" \\(with `inlineScript\\.content`\\) or \"path\" \\(with `path` and a `runType` of (.+?)\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"backend/windmill-api/src/apps_raw_bundler.ts","lineNumber":154,"sourceCode":"\t// The prefixes `execute_component` resolves a run against; anything else is a\n\t// grant no run can match.\n\tconst RUN_TYPES = ['script', 'flow', 'hubscript']\n\tconst malformed = Object.entries(runnables ?? {})\n\t\t.filter(([, r]) => r != null)\n\t\t.filter(([, r]) => {\n\t\t\tif (typeof r !== 'object') return true\n\t\t\tconst run = r as Record<string, any>\n\t\t\tif (run.type === 'inline' || run.type === 'runnableByName') {\n\t\t\t\treturn !nonEmpty(run.inlineScript?.content)\n\t\t\t}\n\t\t\tif (run.type === 'path' || run.type === 'runnableByPath') {\n\t\t\t\treturn !RUN_TYPES.includes(run.runType) || !nonEmpty(run.path)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\t.map(([id]) => id)\n\tif (malformed.length > 0) {\n\t\tthrow new Error(\n\t\t\t`no policy could be derived for runnable(s) ${malformed.join(', ')}: each must be an ` +\n\t\t\t\t`object with a \\`type\\` of \"inline\" (with \\`inlineScript.content\\`) or \"path\" (with ` +\n\t\t\t\t`\\`path\\` and a \\`runType\\` of ${RUN_TYPES.join(', ')})`\n\t\t)\n\t}\n\n\t// The policy's `triggerables_v2` is the allowlist the server matches every run\n\t// against, keyed by a hash of each inline runnable's code. Derived by the\n\t// frontend's own code, bundled into this script by cli/generate-app-policy.ts,\n\t// so the keys are the ones the app editor writes: anything else leaves the\n\t// app's runnables \"forbidden by policy\". Prepended above as a plain `var`, so\n\t// it is in this module's scope (a module's top-level `var` is not a global).\n\tconst { triggerables_v2 } = await __wmillAppPolicy.updateRawAppPolicy(\n\t\trunnables ?? {},\n\t\tundefined\n\t)\n\n\t// Gzipped so a large app's bundle stays well inside MAX_RESULT_SIZE_MB, which","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-api/src/apps_raw_bundler.ts#L136-L172","documentation":"When post-processing the Gemfile.lock to map locked gems to proxied installs, Windmill parses each LOCKED line expecting '<package> <version>'. If a lockfile line does not split into at least package and version tokens, this error names the unparsable line.","triggerScenarios":"install() parses Gemfile.lock lines and a line in the spec/lock section has an unexpected format (empty tokens, unusual gem name with spaces after stripping parentheses, malformed lockfile).","commonSituations":"A corrupted or hand-edited Gemfile.lock; a lockfile generated by an incompatible bundler version with new line formats; a gem whose name/version contains characters the parser doesn't expect.","solutions":["Delete Gemfile.lock locally and regenerate it with bundler lock / bundle install, then redeploy the script","Inspect the named line in the lockfile and fix or remove the malformed entry","Regenerate the lockfile with a bundler version compatible with the worker's Ruby","If a specific gem produces the line, pin it to a version with a standard lockfile representation"],"exampleFix":"# before (hand-edited lockfile line)\n  mygem ()\n# after (regenerate)\n  mygem (1.2.3)","handlingStrategy":"validation","validationCode":"function validateLockfile(lock) {\n  const lines = lock.split('\\n').filter(l => /^\\s{4}\\S/.test(l));\n  for (const l of lines) {\n    const buf = l.replace(/[()]/g, '').trim();\n    const parts = buf.split(/\\s+/);\n    if (parts.length < 2 || !parts[1]) throw new Error(`malformed lock line: \"${l.trim()}\"`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await deployRubyJob({ gemfile, lockfile });\n} catch (e) {\n  if (/Cannot determine version and package name/.test(e.message)) {\n    throw new Error(`Regenerate Gemfile.lock; offending line: ${e.message.split('for: ')[1]}`);\n  }\n  throw e;\n}","preventionTips":["Never hand-edit Gemfile.lock; always regenerate via bundle lock","Generate lockfiles with a bundler version compatible with the worker's Ruby","Commit a valid lockfile with your script"],"tags":["ruby","bundler","lockfile","parsing"],"backgroundTag":"lockfile-parse-error","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}