A fix I wrote and then withdrew

NServiceBus's delayed-messages poller retries without backoff when lock acquisition fails with a non-409 error. I filed the bug, wrote the two-file fix — and then read the CLA's indemnification clause and withdrew the PR.

Today’s find: when NServiceBus’s Azure Storage Queues transport fails to acquire the delayed-messages lock with anything other than 409 Conflict — a 403 from credentials that can’t create the lock container, a storage firewall denying the client — the exception escapes to an outer loop that logs a warning and immediately polls again. No backoff on that path: one storage request per round trip, per endpoint, for as long as the error persists. The existing BackoffOnError is applied on the other failure paths; this one just misses it.

And every one of those requests is a billable Azure Storage transaction. This isn’t a wasted-CPU bug — it’s a bug that shows up on the affected user’s Azure invoice, one transaction at a time, for as long as the error lasts.

The bug report: retry without backoff on non-409 lock failures

Filed as NServiceBus.AzureStorageQueues#1500 with the fix as #1501 — +92/−0, apply the existing backoff in that catch block, with tests for the backoff and for clean cancellation during it.

Then I read the CLA. This is the clause, verbatim:

If I violate another’s rights, liability lies with me. I agree to defend, indemnify, and hold NSB and its users harmless from any claim or demand, including reasonable attorney fees, made by any third party due to or arising out of my violation of these terms and conditions or my violation of the rights of another person or entity.

Here is why that stopped me, specifically. This patch sits exactly on a billing path: the bug is a loop of billable storage transactions, and my change decides how often that loop runs. If I get the backoff subtly wrong, the failure mode isn’t a crash — it’s somebody’s Azure bill. Agreeing to defend and indemnify the project and its users against claims, attorney fees included, while touching the code that drives their cloud costs, is precisely the exposure that clause describes. However confident I am in 92 lines, I don’t want to be anywhere near other people’s money on those terms.

So I withdrew the PR with a note quoting that clause and asking for my CLA signature to be removed, and left the issue and the analysis open — the fix is described precisely enough that a maintainer can reimplement it in minutes.

Two lessons, cheaply bought:

  1. Read the CLA before writing the patch. argo-cd’s DCO is a sign-off that the code is yours to give. An indemnification CLA is an open-ended liability transfer. They are not the same kind of document, and I now check first.
  2. Withdrawing a correct fix still moves the issue forward. The analysis is public, the diff is public, the project can use the idea. Contribution isn’t only merged commits.