# "Unable to deactivate account :: only valid registrations can be deactivated" since 2024-12-18

**URL:** <https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417>\
**Category:** Help\
**Created:** [December 18, 2024, 7:42am UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417 "2024-12-18T07:42:28Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![\_az](https://avatars.discourse-cdn.com/v4/letter/_/22d042/32.png) [@\_az](https://community.letsencrypt.org/u/_az)\
**Post date:** [December 18, 2024, 7:42am UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/1 "2024-12-18T07:42:28Z")

</div>

Hello, long time no see.

I have a nightly CI job that tests a plugin of mine against the staging server.

It is as follows:

```
sudo certbot --staging register -n --no-eff-email \
  --agree-tos --email certbot-dns-multi-nightly@zorin.au
sudo certbot certonly --staging \
  -d "*.zorin.au" -a dns-multi \
  --dns-multi-credentials=/etc/letsencrypt/dns-multi.ini
sudo certbot --staging show_account -vvv
sudo certbot --staging unregister -n -vvv

```

During the `unregister` step, I get the following error:

```json
{
  "type": "urn:ietf:params:acme:error:malformed",
  "detail": "Unable to deactivate account :: only valid registrations can be deactivated",
  "status": 400
}

```

I haven't seen it before, and it now happens on 100% of runs since it first occurred on `2024-12-18 04:31:37 UTC`-ish (I added the account email address after then, sorry).

In the `show_account` step, I get:

```json
JWS payload:
b'{\n "onlyReturnExisting": true,\n "contact": []\n}'
Sending POST request to https://acme-staging-v02.api.letsencrypt.org/acme/new-acct:
{
  "protected": "***",
  "signature": "j_GFoWUDflb99-kBowQSjLxUI5-ZPGjdEpeEkNlnSc_bDVzzi4NfDkDKL4Gu0fc2MjEq7VE17nE7S2NZsFOSORI_62_bie5vMIkPCSnCjAGhVozbjFNn9yztcoTkBvhbcsQGAwbNjEuhSdRGa5xFgdetx6u6mc3epmN3W1v46JRTD2g69GNhFJroR6GW3bmCtpTxG5OewLbdOViIehp_gAmfTr0HOt2LrnInzcNLRdXz_Jk0w1IsmRYcn3t1f2I5uG7GZ-5BWtDa2-KmfVcRVfcEsr49rwhKX6A2BUfGisyK5nFETWsSvANnkK2wV5bV6lFk1CHxa0cR7SmH_fXiqQ",
  "payload": "ewogICJvbmx5UmV0dXJuRXhpc3RpbmciOiB0cnVlLAogICJjb250YWN0IjogW10KfQ"
}
https://acme-staging-v02.api.letsencrypt.org:443 "POST /acme/new-acct HTTP/1.1" 200 535
Received response:
HTTP 200
Server: nginx
Date: Wed, 18 Dec 2024 07:32:59 GMT
Content-Type: application/json
Content-Length: 535
Connection: keep-alive
Boulder-Requester: 176584664
Cache-Control: public, max-age=0, no-cache
Link: <https://acme-staging-v02.api.letsencrypt.org/directory>;rel="index"
Location: https://acme-staging-v02.api.letsencrypt.org/acme/acct/176584664
Replay-Nonce: XCuYn79es3B1HR38m_Qg2dZyzmmIFZik8yq8gu9PKnMj_URmM88
X-Frame-Options: DENY
Strict-Transport-Security: max-age=604800

{
  "key": {
    "kty": "RSA",
    "n": "pHwmQh7xug9DWHLWNdaXQEVo0KKlRFVvFSJS9Ka4TwpEZdSzeRsIBISn4uD1nKrvDwAyDoVbpy04h3vWSza3nu8Ych8u6fFxya2n20KXkUeCHl_u-YtKopAx_N5h-hJgxeXd3kNupe5eUg5a5k5ap8g52NJ9jj3X0Bzq-XB-fDTV6FU3KVuVZSuYC79yo_dMfzjNSQ7Yb3qTxXD3f60_NNpIkXVEw_vPegBhsTS7Vksb5kAvAlOCmG_DH78OcL2_DOX_6ifzNxof8ULdbVEOE9dC1M2tmvsGIxX1PXfOZ84ITvUT0EqhdHbuXhfsnVKrCHA2cHafOBInIBnoMEc8Ew",
    "e": "AQAB"
  },
  "contact": [
    "mailto:certbot-dns-multi-nightly@zorin.au"
  ],
  "createdAt": "2024-12-18T07:31:52Z",
  "status": "valid"
}

```

So, the `status` reported by the server is `valid`, but then the subsequent deregistration step fails:

```json
JWS payload:
b'{\n "status": "deactivated"\n}'
Sending POST request to https://acme-staging-v02.api.letsencrypt.org/acme/acct/176584664:
{
  "protected": "***",
  "signature": "TT9TvxSTdaMIIw202kniqv09sQnp9r-VMZh43kQ9pHV7izNWY3kgmXP_tp5SdQ-L8bIfYH3_ZKsxzOk4TV5n6fFFTay98F_jlPkmYEJCgldXdLvhPLaOgJpPluvl70j-YpLGICW9kpslt2NorQ5S2sPhCVq7fvoQM-SVMnaTInvGQzQmGt_1roedtUyxe9qYl-RHux7t-ULnWHNeENV8kVS_RAeYUcpDNWlNvwatsLEUNvYK-SQN-JoKFbfTMPuJUjlD8ZUXmZalrCL4bdVR87rGIXkbP7YQKugeaYX7zLPJ3ViDmGKEfyXO5I9zIy_lmiXXy5RT7MDPctCpxNo44g",
  "payload": "ewogICJzdGF0dXMiOiAiZGVhY3RpdmF0ZWQiCn0"
}
https://acme-staging-v02.api.letsencrypt.org:443 "POST /acme/acct/176584664 HTTP/1.1" 400 160
Received response:
HTTP 400
Server: nginx
Date: Wed, 18 Dec 2024 07:33:00 GMT
Content-Type: application/problem+json
Content-Length: 160
Connection: keep-alive
Boulder-Requester: 176584664
Cache-Control: public, max-age=0, no-cache
Link: <https://acme-staging-v02.api.letsencrypt.org/directory>;rel="index"
Replay-Nonce: J6d90a-tWaq4ts2NmVA-2Ko0abSAxtU8UXJLUsqR0b8l4sGk_B4

{
  "type": "urn:ietf:params:acme:error:malformed",
  "detail": "Unable to deactivate account :: only valid registrations can be deactivated",
  "status": 400
}

```

It looks like I'm not getting a correct read-after-write.

Any tips? I can always update the job to not deregister, but I don't want to clutter the staging server with a bunch of `valid` accounts. Not too keen on holding long-term account credentials for an account on the CI job either.

---

<div class="post-metadata">

**Author:** ![Osiris](https://avatars.discourse-cdn.com/v4/letter/o/839c29/32.png) [@Osiris](https://community.letsencrypt.org/u/Osiris)\
**Post date:** [December 18, 2024, 10:11am UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/2 "2024-12-18T10:11:45Z")

</div>

If I "Github blame" `wfe.go` where the error is produced, I see a recent PR [wfe: Use separate UpdateRegistrationContact & UpdateRegistrationKey methods by jprenken · Pull Request #7827 · letsencrypt/boulder · GitHub](https://github.com/letsencrypt/boulder/pull/7827) which has modified some code, see [Blaming boulder/wfe2/wfe.go at 11d543bd9878f0624b3929a691ae6aa4838d451b · letsencrypt/boulder · GitHub](https://github.com/letsencrypt/boulder/blame/11d543bd/wfe2/wfe.go#L1464-L1475). Staging currently runs 11d543bd, and that PR is included.

Maybe the culprit?

---

<div class="post-metadata">

**Author:** ![Nummer378](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/nummer378/32/49862_2.png) [@Nummer378](https://community.letsencrypt.org/u/Nummer378)\
**Post date:** [December 18, 2024, 1:14pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/3 "2024-12-18T13:14:32Z")

</div>

Staging was updated to `11d543bd` around 2024-12-17 23:00Z, which is a bit earlier than when \_az reported the first failure. I also had a look at CI and there's a successful run earlier on 2024-12-17, before the update - so the timeline fits quite well with this update causing the error.

---

<div class="post-metadata">

**Author:** ![Osiris](https://avatars.discourse-cdn.com/v4/letter/o/839c29/32.png) [@Osiris](https://community.letsencrypt.org/u/Osiris)\
**Post date:** [December 18, 2024, 2:33pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/4 "2024-12-18T14:33:47Z")

</div>

> [@Nummer378](#):
>
> Staging was updated to `11d543bd` around 2024-12-17 23:00Z

Where did you get this info? 🙂 There's no info on the LE `status.io` about staging updates.

---

<div class="post-metadata">

**Author:** ![Nummer378](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/nummer378/32/49862_2.png) [@Nummer378](https://community.letsencrypt.org/u/Nummer378)\
**Post date:** [December 18, 2024, 2:36pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/5 "2024-12-18T14:36:37Z")

</div>

My own monitoring 😄

[https://germancoding.com/boulder-version-history/](https://germancoding.com/boulder-version-history/)

---

<div class="post-metadata">

**Author:** ![Osiris](https://avatars.discourse-cdn.com/v4/letter/o/839c29/32.png) [@Osiris](https://community.letsencrypt.org/u/Osiris)\
**Post date:** [December 18, 2024, 2:46pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/6 "2024-12-18T14:46:55Z")

</div>

Noice&nbsp;

---

<div class="post-metadata">

**Author:** ![aarongable](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/aarongable/32/42043_2.png) [@aarongable](https://community.letsencrypt.org/u/aarongable)\
**Post date:** [December 18, 2024, 3:41pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/7 "2024-12-18T15:41:04Z")

</div>

Good eye, and thanks for the heads up! I suspect that the diagnosis here is exactly correct; we'll investigate and fix and make sure this doesn't go to prod.

---

<div class="post-metadata">

**Author:** ![Phil](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/phil/32/76801_2.png) [@Phil](https://community.letsencrypt.org/u/Phil)\
**Post date:** [December 18, 2024, 3:54pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/8 "2024-12-18T15:54:30Z")

</div>

The staging boulder has been rolled back downhill.

---

<div class="post-metadata">

**Author:** ![petercooperjr](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/petercooperjr/32/84698_2.png) [@petercooperjr](https://community.letsencrypt.org/u/petercooperjr)\
**Post date:** [December 18, 2024, 4:06pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/9 "2024-12-18T16:06:19Z")

</div>

Just how long have you been waiting to use that pun? Or is it standard terminology amongst the Boulder devs? 🙂

---

<div class="post-metadata">

**Author:** ![Phil](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/phil/32/76801_2.png) [@Phil](https://community.letsencrypt.org/u/Phil)\
**Post date:** [December 18, 2024, 4:08pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/10 "2024-12-18T16:08:42Z")

</div>

The magic flowed out of fingers into the reply as I was typing. Like Michael Scott says, "Sometimes I'll start a sentence, and I don't even know where it's going. I just hope I find it along the way. Like an improv conversation. An improversation.”

---

<div class="post-metadata">

**Author:** ![griffin](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/griffin/32/50204_2.png) [@griffin](https://community.letsencrypt.org/u/griffin)\
**Post date:** [December 18, 2024, 5:12pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/11 "2024-12-18T17:12:04Z")

</div>

> [@Phil](#):
>
> An improversation.

Speaking of... [yes, and...](https://en.m.wikipedia.org/wiki/Yes,_and...) 😉

---

<div class="post-metadata">

**Author:** ![Osiris](https://avatars.discourse-cdn.com/v4/letter/o/839c29/32.png) [@Osiris](https://community.letsencrypt.org/u/Osiris)\
**Post date:** [December 18, 2024, 5:53pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/12 "2024-12-18T17:53:14Z")

</div>

> [@Nummer378](#):
>
> My own monitoring 😄
> 
> [Let's Encrypts Boulder version history](https://germancoding.com/boulder-version-history/)

In combination with:

> [@Phil](#):
>
> The staging boulder has been rolled back downhill.

@Nummer378 Is it a deliberate choice to keep just the single commit entry for rollbacks? I see you use "First seen" and "Last seen", but for me it would make more sense to have a _new_ entry for rollbacks with that certain commit a second time with a new "From" and "To" timestamp.

Maybe even add an exclamation mark with "rollback" title popup so it's clear it was rolled back 🙂

---

<div class="post-metadata">

**Author:** ![Nummer378](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/nummer378/32/49862_2.png) [@Nummer378](https://community.letsencrypt.org/u/Nummer378)\
**Post date:** [December 18, 2024, 6:26pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/13 "2024-12-18T18:26:02Z")

</div>

I don't recall exactly, but I think it was easier this way to cover different scenarios. I do recall a time when LE did some type of A-B testing\* where the client would frequently flip-flop between two different Boulder versions. Describing that as a "rollback" every time an old version reappeared would quite quickly overload the table, so I went with just a single entry. The drawback is, as you've realized, that multiple rollbacks are very difficult to reconstruct from the data set.

\*It may also have been due to different DC's running slightly different build IDs, I don't know for sure.

---

<div class="post-metadata">

**Author:** ![Osiris](https://avatars.discourse-cdn.com/v4/letter/o/839c29/32.png) [@Osiris](https://community.letsencrypt.org/u/Osiris)\
**Post date:** [December 18, 2024, 6:27pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/14 "2024-12-18T18:27:41Z")

</div>

Hmm, but how often would that be the case?

Also maybe some "grace period" might help there..? Just thinking out loud 🙂

That said, I suspect there would be a third commit after a rollback, so it's possible to reconstruct where the rollback was..

I.e., if the commits after reach other were A -\> B -\> C and B was rolled back to A with the reason for the rollback fixed in C, the "First seen" and "Last seen" times of B would be in the middle of the "First seen" and "Last seen" of A. I.e., the timestamps of A would be before and after the respective timestamps of B. And the "First seen" from C would correspond with the _new_ "Last seen" of A, while the now missing earlier "Last seen" of A corresponds with the "First seen" of B.. So it is possible to reconstruct the events.

---

<div class="post-metadata">

**Author:** ![mcpherrinm](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/mcpherrinm/32/59604_2.png) [@mcpherrinm](https://community.letsencrypt.org/u/mcpherrinm)\
**Post date:** [December 18, 2024, 8:28pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/15 "2024-12-18T20:28:46Z")

</div>

We "Canary" a new release for a few moments and verify it's working properly before doing a full deploy, and the deploy itself is rolling, so there is often periods where two releases are running. Even the public endpoint is just the "WFE" component, not the full stack.

The deploy process for each DC is also independent, so there may be a period of time where there's two releases running in prod (we only have 1 staging)

Here's what it looks like in terms of running processes (though the old processes that are in the process of shutdown don't show up here so it's not 100% right):

 ![image](https://global.discourse-cdn.com/letsencrypt/original/3X/3/9/39e1b8c4460f95976f34f8a46570e08d6740aab7.png)

You can see the big vertical spike as the canaries come up, a (mostly) flat line as we wait for the canary period, and then a big yellow drop as we start swapping out the old release

---

<div class="post-metadata">

**Author:** ![Osiris](https://avatars.discourse-cdn.com/v4/letter/o/839c29/32.png) [@Osiris](https://community.letsencrypt.org/u/Osiris)\
**Post date:** [December 18, 2024, 8:35pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/16 "2024-12-18T20:35:31Z")

</div>

Looks like that s all done within the hour, perhaps even on a scale of minutes if the next value on the X-axis is "23:20".

---

<div class="post-metadata">

**Author:** ![mcpherrinm](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/mcpherrinm/32/59604_2.png) [@mcpherrinm](https://community.letsencrypt.org/u/mcpherrinm)\
**Post date:** [December 18, 2024, 8:38pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/17 "2024-12-18T20:38:54Z")

</div>

Yes, that's times at the bottom, so that staging deploy started at 23:13 and finished at 23:18 UTC. So about 5 minutes. Double that in prod assuming we do the DCs sequentually, plus any time we might wait in between.

---

<div class="post-metadata">

**Author:** ![Osiris](https://avatars.discourse-cdn.com/v4/letter/o/839c29/32.png) [@Osiris](https://community.letsencrypt.org/u/Osiris)\
**Post date:** [December 18, 2024, 9:08pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/18 "2024-12-18T21:08:45Z")

</div>

Sounds like an hour as "grace period" for @Nummer378 s history application would be more than enough (overkill probably) to prevent erroneous entries in that history.

Assuming no AB-testing is going to happen any time soon without prior warning.

* * *

On another note (and more on topic): seems like @aarongable fixed this bug in [Fix error when deactivating an account by aarongable · Pull Request #7899 · letsencrypt/boulder · GitHub](https://github.com/letsencrypt/boulder/pull/7899). 🥳

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/letsencrypt/original/3X/c/a/ca6c06ea1ea201324bba7048c6841ce60236468d.png) [@system](https://community.letsencrypt.org/u/system)\
**Post date:** [January 17, 2025, 9:09pm UTC](https://community.letsencrypt.org/t/unable-to-deactivate-account-only-valid-registrations-can-be-deactivated-since-2024-12-18/230417/19 "2025-01-17T21:09:23Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
