# SC301：服务退出码错误

> SC301（服务退出码错误）表示进程退出时的退出码不是 shutdown.exitCode，或者进程被信号杀死。本文说明这两种情况的修复方法。

Source: https://shutdown.jscrate.dev/zh/docs/codes/sc301
Last updated: 2026-09-23

`SC301` 表示服务按时停止了，但退出结果与 `shutdown.exitCode` 不一致。服务可能返回了非零退出码，也可能直接因信号而终止。

| | |
| --- | --- |
| 诊断码 | `SC301` (FAIL) |
| 阶段 | 进程退出 |
| CLI 退出码 | 1 |
| 含义 | 进程退出了，但退出码与 `shutdown.exitCode` 不同，或者进程被信号杀死。 |
| 输出信息 | `Service process failed: <error>`<br>`Service exited with code <code> and signal <signal>; expected code <shutdown.exitCode>` |
| 首先检查 | 自己处理 SIGTERM，避免 Node 因该信号直接退出；并检查清理过程中是什么设置了 `process.exitCode`。 |

## 时间线说明了什么？

- `code=1, signal=none`：应用代码设置了表示失败的退出码。
- `code=null, signal=SIGTERM`：通常说明没有生效的信号处理函数。
- 其他信号名：说明进程崩溃了，或者被外部杀死。

## 如何修复？

在实际运行服务器的那个进程上注册 `SIGTERM` 处理函数。只在清理失败时设置 `process.exitCode`，并到 stderr 中查看原始错误。

如果非零退出是有意为之，把 `shutdown.exitCode` 设为那个值。不过大多数服务在计划内的关闭之后仍应以 `0` 退出，因为进程管理器会把非零退出码当作崩溃。

## 如何确认已修复？

时间线应显示配置的退出码和 `signal=none`。同时检查服务日志：退出码正常，但背后藏着清理错误，这不算健康的关闭。

如果仍然是 `signal=SIGTERM`，确认监听器注册在真正的服务器进程上，而不只是在父级包装进程上。

## 相关内容

- [在 Node.js 中处理 SIGTERM](https://shutdown.jscrate.dev/zh/docs/guides/graceful-shutdown-nodejs)
- [退出码配置](https://shutdown.jscrate.dev/zh/docs/configuration#shutdown)
- [SC300：服务未退出](https://shutdown.jscrate.dev/zh/docs/codes/sc300)
- [SC302：端口仍未关闭](https://shutdown.jscrate.dev/zh/docs/codes/sc302)
