{"record":{"id":"a4f0ef8ae51ad686","repo":"paperclipai/paperclip","slug":"options-errorlabel-decision-predicate-failed-a4f0ef","errorCode":null,"errorMessage":"${options.errorLabel} decision predicate failed: ${detail}","messagePattern":"(.+?) decision predicate failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/adapters/grok-local/src/server/grok-auth-merge-decision.ts","lineNumber":70,"sourceCode":"  destinationPath: string,\n  options: DecideGrokAuthMergeOptions,\n): Promise<number> {\n  try {\n    await execFile(\"node\", [DECISION_SCRIPT_PATH, sourcePath, destinationPath]);\n  } catch (error) {\n    const code = (error as { code?: unknown }).code;\n    if (typeof code === \"number\" && KNOWN_EXIT_CODES.has(code)) {\n      return code;\n    }\n    const detail =\n      typeof code === \"string\"\n        ? `node could not be executed (${code})`\n        : typeof code === \"number\"\n          ? `unexpected predicate exit code ${code}`\n          : error instanceof Error\n            ? error.message\n            : String(error);\n    throw new Error(`${options.errorLabel} decision predicate failed: ${detail}`);\n  }\n  // `execFile` resolved, so the predicate exited 0. The predicate always\n  // exits 10, 20, 21, or 22, so a clean exit 0 is unexpected; fail loud.\n  throw new Error(\n    `${options.errorLabel} decision predicate exited 0 (expected 10, 20, 21, or 22)`,\n  );\n}\n","sourceCodeStart":52,"sourceCodeEnd":78,"githubUrl":"https://github.com/paperclipai/paperclip/blob/5716fe907e596ce73501408fc6efdb19fb61edf2/packages/adapters/grok-local/src/server/grok-auth-merge-decision.ts#L52-L78","documentation":"decideGrokAuthMerge runs a child `node` predicate (grok-auth-merge-decision.cjs) that must exit 10, 20, 21, or 22. If the process fails to spawn, crashes with another exit code, or errors, the wrapper throws this labeled error so a broken predicate is never silently treated as a merge decision. The message embeds the underlying detail (spawn failure, unexpected exit code, or error message).","triggerScenarios":"`node` is not on PATH or not executable (code is a string like ENOENT/EACCES); the predicate script crashed with an exit code outside {10,20,21,22} (e.g. uncaught exception → exit 1); the .cjs file is missing from the build output.","commonSituations":"Deploying/packaging without copying grok-auth-merge-decision.cjs; running in an environment without node in PATH (bundled/electron runtime); corrupted source/destination paths causing the predicate to throw; syntax error in a locally patched predicate.","solutions":["Confirm `node --version` works in the same environment the server runs in; install node or fix PATH.","Verify grok-auth-merge-decision.cjs exists next to the compiled module (check your build/bundling step).","Run the predicate manually: `node grok-auth-merge-decision.cjs <src> <dst>; echo $?` to see the real crash.","Fix the source/destination paths passed in if the predicate is crashing on file access."],"exampleFix":"// before: spawn fails because node is missing in the packaged app\nawait execFile(\"node\", [script, src, dst]);\n// after: resolve an explicit runtime and verify availability first\nconst nodeBin = process.env.NODE_BIN ?? \"node\";\nawait execFile(nodeBin, [script, src, dst]); // and ship the .cjs with the bundle","handlingStrategy":"try-catch","validationCode":"// pre-flight: node exists and the predicate script is present\nimport { accessSync, constants } from \"node:fs\";\ntry { accessSync(DECISION_SCRIPT_PATH, constants.X_OK); } catch { throw new Error(\"decision predicate missing: \" + DECISION_SCRIPT_PATH); }\nawait execFile(\"node\", [\"--version\"]); // throws ENOENT if node is unavailable","typeGuard":"function isSpawnError(e: unknown): e is NodeJS.ErrnoException {\n  return e instanceof Error && typeof (e as NodeJS.ErrnoException).code === \"string\";\n}","tryCatchPattern":"try {\n  const code = await decideGrokAuthMerge(src, dst, { errorLabel: \"grok auth copy-out\" });\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"decision predicate failed\")) {\n    // never assume \"keep destination\" — a broken predicate is a hard failure\n    log.error(e.message); // includes node spawn error or unexpected exit code\n  }\n  throw e;\n}","preventionTips":["Ship grok-auth-merge-decision.cjs with your build/bundle and verify it post-install.","Ensure node is on PATH in the runtime (containers, packaged apps).","Never edit the predicate without keeping its exit-code contract (10/20/21/22).","Smoke-test the predicate on fixture files at startup."],"tags":["child-process","node","exit-code","predicate","auth"],"backgroundTag":"unexpected-exit-code","analyzedSha":"5716fe907e596ce73501408fc6efdb19fb61edf2","analyzedAt":"2026-09-02T18:44:00.616Z","contentChangedAt":"2026-09-02T18:44:00.616Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}