System Program Development: Where Exactly Is the Boundary Between Error Codes and Exceptions?
Why We Keep Debating Over Error Codes vs. Exceptions
In system program development in 2026, error handling style remains a major source of team disagreement. Many production failures are not caused by functional logic but by mixing error codes and exceptions: a low-level timeout is thrown as an exception to the upper layer, causing the entire service to interrupt, whereas returning a retry marker would allow the problem to be recovered locally. This stems from fundamentally different positioning of "error responsibility" between the two styles.
Error codes treat errors as return results that the caller must explicitly handle; exceptions treat errors as program flow, caught uniformly by an upper layer. When developers switch mindsets within the same module, code turns into "spaghetti logic." Only by understanding this difference can we discuss how to choose.
- Error codes: Explicit and predictable, suitable for low-level libraries and performance-sensitive paths.
- Exceptions: Reduce boilerplate and unify error handling, suitable for business logic and module boundaries.
Comparison of Error Codes and Exceptions
Placing them in the same table clarifies the dimensional differences. The following four contrasts cover the key decision points.
- Propagation method: Error codes require layer-by-layer checking; exceptions jump the stack directly to the catch point.
- Performance overhead: Error codes have almost zero cost; exceptions expand the call stack at runtime, which is noticeable in embedded systems or high-frequency loops.
- Code structure: Error codes add an extra check branch at each call site; exceptions make business code cleaner but hide the path.
- Recovery responsibility: Error codes allow the caller to immediately decide recovery; exceptions push responsibility to higher layers, and the point of error may be far from the handling point.
In 2026 practice, a common compromise is to return error codes at the bottom and convert them to exceptions at module entrances, or wrap error codes with a Result type to balance clarity and performance.
Four-Dimensional Decision Method: Decide Style by Order
Rather than arguing, use the four-dimensional decision method. The four dimensions are error ownership layer, propagation distance, recovery action, and performance sensitivity. Following this order, if each question can be answered clearly, the style is determined.
- Error ownership layer: Can the current function handle the error, or must the upper layer handle it? If the current function can handle it, use error codes; if the upper layer must handle it, use exceptions.
- Propagation distance: How many layers does the error need to cross? If more than three layers, exceptions are more convenient; otherwise, error codes are more direct.
- Recovery action: Does recovery simply return a default value, or does it require retry, degradation? Simple recovery uses error codes; complex strategies use exceptions.
- Performance sensitivity: Is the path latency requirement at microsecond level? If so, avoid exceptions.
The boundary of this framework lies in: if the four dimensions contradict each other, prioritize performance sensitivity and error ownership layer. For example, even if errors propagate far in a kernel-mode driver, try to use error codes because exceptions are not available in interrupt context. When Xiyue Company delivers embedded projects, it uniformly requires that the driver layer prohibit throwing exceptions.
Common Pitfalls and Counterexamples
Many poorly written error handling is not due to wrong selection but to avoiding these pitfalls. The following are the most common ones encountered in 2026 projects.
- Swallowing errors: After catch, only log without recovery, hiding the problem until it becomes irreversible.
- Undefined error codes: Returning -1 or 255 without explaining the meaning, forcing guesswork during troubleshooting.
- Throwing across boundaries: In languages that support exceptions but the underlying system does not, such as C++ calling C libraries, exceptions crossing the extern "C" boundary can crash directly.
- Treating business exceptions as assertions: Using exceptions for normal business branches causes performance degradation and reading confusion.
Rules corresponding to counterexamples: Error codes must carry context, with documentation for each value; exceptions must be caught and record the call chain, not just log the message; when crossing system boundaries, translate exceptions into error codes at the boundary.
How to Evaluate Whether Error Handling Is Well-Written
Good error handling has objective standards. You can use the following five questions to check existing code; passing all with "yes" is the minimum.
- Does the error message include the location and source of the error?
- Is the caller forced or clearly prompted to handle the error?
- After recovery, can the system return to a consistent state?
- Can the error handling code be unit tested?
- Does the performance-sensitive path avoid exception propagation?
Practical recommendation: Add an error code coverage check in CI; if an error code is not handled, the build fails. This is more effective than any code style guide.
Applicable Scenarios and Boundaries
In system program development in 2026, the "appropriate scope" for error handling styles is already clear. Scenarios suitable for error codes include protocol parsing, hardware drivers, network stacks, thread pool internals, and high-frequency loops. Scenarios suitable for exceptions include application-layer business orchestration, batch tasks, external service calls, and complex retry strategies.
Do not force unification: if a project is primarily based on error codes, do not introduce exceptions for the sake of being "modern" and break consistency; vice versa. The key is to define conversion rules clearly at module boundaries and document them. For small utility scripts or one-off migration scripts, writing with exceptions is faster.
Frequently Asked Questions
Can error codes and exceptions be mixed?
Yes, but explicit conversion must be done at module boundaries, stipulating that the underlying layer uses error codes, converts them uniformly to exceptions when entering the business layer, and records context.
Which style do mainstream systems use in 2026?
Low-level libraries (such as operating systems, runtimes) commonly use error codes, like returning errno; application-level frameworks mostly use exceptions. Both are likely to coexist.
Do error codes need to be globally unified?
Yes. The global error code table should include module prefixes, error levels, and recovery recommendations, avoiding the situation where the same number has different meanings in different modules.
Do exceptions really affect performance?
In hot loops or high-frequency calls, exception expansion can cost several times more. If you need microsecond-level control, using error codes or Result types is more stable.
Should retry logic be placed in error codes or exceptions?
It is recommended to put it on the error code side, because retry is an explicit recovery action; exception-side retry tends to hide the retry count limit, leading to failure amplification.
Action guide: First draw a dependency graph for the current project, marking low-level modules and application layers, then determine the error handling style layer by layer using the four-dimensional decision method, write conversion rules at module boundaries, and finally use error code coverage checks to ensure implementation. Suitable for systems with high complexity and long-term iteration; if it is just a demo project or a CRUD microservice, avoid over-designing any specifications.
-
Unit Test Coverage in System Program Development: Is Higher Always Better?
Date: Aug 14, 2026 Read: 5
-
System Program Development: What's the Difference Between a Configuration Center and Configuration Files?
Date: Aug 13, 2026 Read: 8
-
System Program Development Log Framework Selection: How to Choose and Implement in 2026
Date: Aug 11, 2026 Read: 14
-
How to Approach System Program Development: Process, Technology Selection, and Common Pitfalls
Date: Aug 10, 2026 Read: 18
-
A Practical Guide to System Program Development: Processes, Tools, and Selection Boundaries
Date: Aug 9, 2026 Read: 20




