{"record":{"id":"77d657004c599800","repo":"DIYgod/RSSHub","slug":"exec-is-not-supported-in-cloudflare-workers","errorCode":null,"errorMessage":"exec is not supported in Cloudflare Workers","messagePattern":"exec is not supported in Cloudflare Workers","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/shims/node-child-process.ts","lineNumber":10,"sourceCode":"// Worker-specific shim for node:child_process\n// This module is not available in Cloudflare Workers\n\nexport function execSync(_command: string): Buffer {\n    // Return empty buffer - git info will fall back to 'unknown'\n    return Buffer.from('');\n}\n\nexport function exec() {\n    throw new Error('exec is not supported in Cloudflare Workers');\n}\n\nexport function spawn() {\n    throw new Error('spawn is not supported in Cloudflare Workers');\n}\n","sourceCodeStart":1,"sourceCodeEnd":16,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/shims/node-child-process.ts#L1-L16","documentation":"Intentional guard in the Cloudflare Workers shim for node:child_process (lib/shims/node-child-process.ts). The Workers runtime cannot spawn OS processes, so exec() throws immediately when called. Note execSync() is deliberately NOT throwing — it returns an empty Buffer so git-info lookups degrade to 'unknown' instead of crashing.","triggerScenarios":"Any code path that calls child_process.exec(...) (async shell-out) while running the Cloudflare Workers build of RSSHub — e.g. a route that runs an external binary, or a transitive dependency that probes the shell.","commonSituations":"A route written for Node that shells out; Puppeteer-style launch wrappers; a library that runs `git`/`hostname` via exec; deploy target switched from Node to Workers without auditing shell usage.","solutions":["Avoid calling exec() in code paths deployed to Workers.","Gate the call behind a runtime check (Node vs Workers) and skip it under Workers.","If a degraded value is acceptable, mirror execSync's pattern: return a safe empty default instead of throwing.","Move the offending route to the Node deployment target."],"exampleFix":"// before\nimport { exec } from 'node:child_process';\nexec('git rev-parse --short HEAD', cb);\n// after\nimport { execSync } from 'node:child_process';\n// execSync is shimmed to return '' under Workers\nconst sha = execSync('git rev-parse --short HEAD').toString().trim() || 'unknown';","handlingStrategy":"validation","validationCode":"// detect Workers runtime before any exec() call\nconst isWorkers =\n  typeof navigator !== 'undefined' &&\n  (navigator.userAgent?.includes('Cloudflare-Workers') ||\n   // @ts-expect-error global only in Workers\n   typeof caches !== 'undefined' && typeof process === 'undefined');\nif (isWorkers) {\n  // skip exec(); fall back to a static/empty value\n}","typeGuard":"function canExec(): boolean {\n  return typeof process !== 'undefined' && !!process.versions?.node;\n}","tryCatchPattern":"try {\n  if (canExec()) {\n    // real exec only on Node\n  } else {\n    return ''; // Workers-safe fallback\n  }\n} catch (e) {\n  if (e instanceof Error && /not supported in Cloudflare Workers/.test(e.message)) return '';\n  throw e;\n}","preventionTips":["Prefer execSync (shimmed to empty) over exec where a degraded value is fine.","Audit shell-out calls before deploying a route to Workers.","Gate subprocess code behind a Node-runtime check."],"tags":["cloudflare-workers","child-process","runtime","shim"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}