# The pandemic of incomplete OpenSSL error handling

A short, pointed post by Julian Andres Klode (APT maintainer) arguing that a widely-copied OpenSSL "best practice" is a systemic, dangerous anti-pattern: sprinkling `ERR_clear_error()` around TLS operations to make inconvenient errors disappear.

## The trigger

Someone reported that TLS in APT was failing on FIPS systems with MD5 errors and suggested wrapping TLS operations in `ERR_clear_error()`. Klode refused, on the principle that one component failing to handle its errors doesn't license discarding *all* errors somewhere else — the program should have failed earlier, or discarded the specific error only once it was determined safe. He then discovered this workaround has been treated as a best practice for years: codebases everywhere call `ERR_clear_error()` before TLS operations, and OpenSSL upstream itself suggests doing so.

## The core mistake: OpenSSL has an error *stack*

The root problem is that many authors don't realize OpenSSL maintains a *stack* of errors, not a single error slot. Two anti-patterns follow:

1. **Blanket clearing.** Call `ERR_clear_error()` before a TLS operation to wipe whatever is on the stack. This silently discards *unrelated* errors that were left there by earlier code — errors that may signal a real problem. The error that caused the entry should be fixed (or handled where it occurred), not swept away later because it's now inconvenient.
2. **Check-the-top-then-discard.** Call an OpenSSL operation, inspect the top-level error, and if it's deemed "not too bad," discard the whole stack. Same defect: unrelated errors below the top get silently thrown away.

Both patterns convert "an error happened somewhere" into "no error," which is exactly the failure that breaks trust in security-sensitive code. This is the [[error-stack-anti-pattern]] — discarding an entire error channel to suppress one entry.

## The fix

Use OpenSSL's mark mechanism to scope your own error context instead of clearing globally: `ERR_set_mark()` to push a mark, then `ERR_pop_to_mark()` to pop back to it — a guard around a group of OpenSSL operations that removes only the errors *you* generated, leaving anything from other code intact. Klode's call to action: audit your codebase for every `ERR_clear_error()` call and determine whether it's safe or one of the bad patterns above; and to OpenSSL's authors, stop encouraging practices that "fundamentally break any trust in software."

## Why it matters beyond OpenSSL

The general lesson is about error-handling hygiene at library boundaries: when a library exposes a shared, stateful error channel, "clear it so my happy path works" is nearly always wrong, because you're discarding information that belongs to other code. Relatedly, it's the kind of subtle, easy-to-get-wrong C error handling that [[reviewing-ai-code]] and [[testing-heavy-no-review-workflow]] both flag as hard to catch by review alone — the anti-pattern spread precisely because it looks locally correct and passes review. Compare the broader supply-chain-and-correctness concerns in [[supply-chain-security]].
