All writing
Debugging·2 min read·May 14, 2026

The Error Message Was Lying

A Salesforce JWT auth failure that had nothing to do with JWT, Salesforce, or auth. On reading errors as evidence rather than instructions.

DebuggingOAuthProduction

The application authenticated against Salesforce perfectly on my machine. In production it failed every time, with an error about an invalid JWT assertion.

That error is a good error. It is specific, it names a real thing, and it sent me in completely the wrong direction for most of a day.

What I checked first, and why it was wasted

An invalid assertion means the signature is wrong. So: the algorithm, the claim set, the audience URL, the clock skew between the server and Salesforce, the Connected App configuration, the certificate uploaded against it. All correct. All checked twice, because when the obvious answer isn't there the first instinct is to look at the obvious answer again, harder.

The problem with a specific error message is that it tells you what the last component in the chain concluded. It says nothing about what the components before it handed over.

What was actually wrong

The private key was being truncated on its way into the process environment. What arrived at the signing function was a fragment of a key — enough to look like a key, not enough to produce a valid signature.

Salesforce was reporting exactly what it saw: a bad signature. Its error was accurate. It was just describing the last link of a chain that had broken three links earlier.

The habit worth building

When an error names a component, treat that as the end of the trail, not the start. Work backwards down the stack and check what each layer actually received, rather than forwards from the message toward things that could plausibly cause it.

Concretely, for this class of bug: log the length and the first and last characters of every secret at the moment of use. Never the secret. Just its shape. A key that should be 1,704 characters and is 1,024 tells you everything in one line, and it would have saved me a day.

The second one

The same deployment then failed to issue an SSL certificate. Certbot's error looked like a Certbot problem. It was a DNSSEC validation conflict — again, a component accurately reporting the failure of something upstream of it.

Twice in one week, the same lesson. Errors are evidence, not instructions. They tell you where the failure surfaced, and almost never where it started.