{"record":{"id":"55da507ec6cf4d3a","repo":"denoland/deno","slug":"err-unknown-signal","errorCode":"ERR_UNKNOWN_SIGNAL","errorMessage":"Unknown signal: ${signal}","messagePattern":"Unknown signal: (.+?)","errorType":"error_code","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/child_process.ts","lineNumber":1022,"sourceCode":"      return \"null\";\n    case \"inherit\":\n      return \"inherit\";\n    case \"ipc\":\n      return \"ipc_for_internal_use\";\n    default:\n      throw new ERR_INVALID_ARG_VALUE(\"stdio\", pipe);\n  }\n}\n\nfunction toDenoSignal(signal) {\n  const nodeSignals = os.signals;\n  if (typeof signal === \"number\") {\n    for (const name of new SafeArrayIterator(keys(nodeSignals))) {\n      if (nodeSignals[name] === signal) {\n        return name;\n      }\n    }\n    throw new ERR_UNKNOWN_SIGNAL(String(signal));\n  }\n\n  if (ReflectHas(nodeSignals, signal)) {\n    return signal;\n  }\n  // On Windows, os.signals only lists native signals. Accept any\n  // POSIX signal name so the caller can remap it to SIGTERM.\n  if (isWindows && StringPrototypeStartsWith(signal, \"SIG\")) {\n    return signal;\n  }\n  throw new ERR_UNKNOWN_SIGNAL(signal);\n}\n\nfunction keys(object) {\n  return ObjectKeys(object);\n}\n\nfunction copyProcessEnvToEnv(","sourceCodeStart":1004,"sourceCodeEnd":1040,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/child_process.ts#L1004-L1040","documentation":"toDenoSignal() resolves a NUMERIC signal to a name by scanning os.signals (name → number). If no signal name maps to that number, ERR_UNKNOWN_SIGNAL is thrown with the number stringified. Only numbers present in the os.signals table (1–31-ish POSIX values like 9 for SIGKILL, 15 for SIGTERM) are accepted; 0 and out-of-range values like 99 are not.","triggerScenarios":"child.kill(0) used as a liveness probe (signal 0 has no named entry); child.kill(99); signal values computed from arithmetic or read from config/protocol fields without validation.","commonSituations":"Porting Unix liveness checks that rely on kill(pid, 0) semantics; signal numbers forwarded from another service or IPC message; assuming any 1–64 number is valid because Linux accepts it at the syscall level.","solutions":["Use named signals: child.kill('SIGTERM'), child.kill('SIGKILL')","Derive numbers only from os.signals / os.constants.signals so they always resolve (e.g. os.constants.signals.SIGTERM)","For liveness checks, test child.exitCode !== null or wrap kill() in try/catch instead of using signal 0"],"exampleFix":"// before\nchild.kill(0); // probe for liveness\n\n// after\nconst alive = child.exitCode === null && child.signalCode === null;\n// and when terminating:\nchild.kill('SIGTERM');","handlingStrategy":"validation","validationCode":"import os from 'node:os';\nfunction toSignalName(sig) {\n  if (typeof sig === 'number') {\n    const entry = Object.entries(os.signals).find(([, n]) => n === sig);\n    if (!entry) throw new Error(`unsupported signal number ${sig}`);\n    return entry[0];\n  }\n  return sig;\n}","typeGuard":"import os from 'node:os';\nconst isValidSignalNumber = (n) =>\n  typeof n === 'number' && Object.values(os.signals).includes(n);","tryCatchPattern":"try { child.kill(sig); } catch (err) {\n  if (err?.code === 'ERR_UNKNOWN_SIGNAL') {\n    child.kill('SIGTERM'); // safe portable default\n  }\n}","preventionTips":["Prefer named signals ('SIGTERM', 'SIGKILL') over numbers","Use signal 0 only via try/catch liveness probes, never as a real kill target here","Validate numbers against os.signals before forwarding them from other systems"],"tags":["child-process","signals","node-compat","deno","process-kill"],"backgroundTag":"unknown-signal","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}