Repository: certbot/certbot (language: python)

Issue:
certbot-dns-ovh failed with Error adding TXT record: Expecting value: line 1 column 1 (char 0)
## My operating system is (include version):

MacoSX 13.6 using docker latest image : https://hub.docker.com/r/certbot/dns-ovh

## I installed Certbot with (snap, OS package manager, pip, certbot-auto, etc):

Docker

## I ran this command and it produced this output:

Command :
docker run -it --rm --name certbot \
            -v "/Users/mguyard/Documents/Docker/certbot/etc/letsencrypt:/etc/letsencrypt" \
            -v "/Users/mguyard/Documents/Docker/certbot/var/lib/letsencrypt:/var/lib/letsencrypt" \
            certbot/certbot certonly --dns-ovh --dns-ovh-credentials "/etc/letsencrypt/.ovhapi" --non-interactive --agree-tos --email me@mydomain.com -d '*.mydomain.com' --logs-dir "/etc/letsencrypt/logs" --config-dir "/etc/letsencrypt/config" --work-dir "/etc/letsencrypt/work" -v

Result :
```
Saving debug log to /etc/letsencrypt/logs/letsencrypt.log
Plugins selected: Authenticator dns-ovh, Installer None
Certificate is due for renewal, auto-renewing...
Renewing an existing certificate for *.mguyard.com
Performing the following challenges:
dns-01 challenge for mguyard.com
Cleaning up challenges
Error adding TXT record: Expecting value: line 1 column 1 (char 0)
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /etc/letsencrypt/logs/letsencrypt.log or re-run Certbot with -v for more details.
```


## Certbot's behavior differed from what I expected because:

Certificate end with error and isn't renew

## Here is a Certbot log showing the issue (if available):
###### Logs are stored in `/var/log/letsencrypt` by default. Feel free to redact domains, e-mail and IP addresses as you see fit.

```
2023-10-12 17:11:48,231:DEBUG:certbot._internal.main:certbot version: 2.7.1
2023-10-12 17:11:48,231:DEBUG:certbot._internal.main:Location of certbot entry point: /usr/local/bin/certbot
2023-10-12 17:11:48,231:DEBUG:certbot._internal.main:Arguments: ['--dns-ovh', '--dns-ovh-credentials', '/etc/letsencrypt/.ovhapi', '--non-interactive', '--agree-tos', '--email', 'marc@mydomain.com', '-d', '*.mydomain.com', '--logs-dir', '/etc/letsencrypt/logs', '--config-dir', '/etc/letsencrypt/config', '--work-dir', '/etc/letsencrypt/work', '-v']
2023-10-12 17:11:48,231:DEBUG:certbot._internal.main:Discovered plugins: PluginsRegistry(PluginEntryPoint#dns-ovh,PluginEntryPoint#manual,PluginEntryPoint#null,PluginEntryPoint#standalone,PluginEntryPoint#webroot)
2023-10-12 17:11:48,318:DEBUG:certbot._internal.log:Root logging level set at 20
2023-10-12 17:11:48,321:DEBUG:certbot._internal.plugins.selection:Requested authenticator dns-ovh and installer None
2023-10-12 17:11:48,322:DEBUG:certbot._internal.plugins.selection:Single candidate plugin: * dns-ovh
Description: Obtain certificates using a DNS TXT record (if you are using OVH for DNS).
Interfaces: Authenticator, Plugin
Entry point: EntryPoint(name='dns-ovh', value='certbot_dns_ovh._internal.dns_ovh:Authenticator', group='certbot.plugins')
Initialized: <certbot_dns_ovh._internal.dns_ovh.Authenticator object at 0xffff8fefa410>
Prep: True
2023-10-12 17:11:48,322:DEBUG:certbot._internal.plugins.selection:Selected authenticator <certbot_dns_ovh._internal.dns_ovh.Authenticator object at 0xffff8fefa410> and installer None
2023-10-12 17:11:48,322:INFO:certbot._internal.plugins.selection:Plugins selected: Authenticator dns-ovh, Installer None
2023-10-12 17:11:48,367:DEBUG:certbot._internal.main:Picked account: <Account(RegistrationResource(body=Registration(key=None, contact=(), agreement=None, status=None, terms_of_service_agreed=None, only_return_existing=None, external_account_binding=None), uri='https://acme-v02.api.letsencrypt.org/acme/acct/728015997', new_authzr_uri=None, terms_of_service=None), 17a77fe8ee348e150aac144f5edce683, Meta(creation_dt=datetime.datetime(2022, 9, 12, 8, 25, tzinfo=<UTC>), creation_host='3bbceec2dec9', register_to_eff=None))>
2023-10-12 17:11:48,368:DEBUG:acme.client:Sending GET request to https://acme-v02.api.letsencrypt.org/directory.
2023-10-12 17:11:48,369:DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org:443
2023-10-12 17:11:49,128:DEBUG:urllib3.connectionpool:https://acme-v02.api.letsencrypt.org:443 "GET /directory HTTP/1.1" 200 752
2023-10-12 17:11:49,129:DEBUG:acme.client:Received response:
HTTP 200
Server: nginx
Date: Thu, 12 Oct 2023 17:11:49 GMT
Content-Type: application/json
Content-Length: 752
Connection: keep-alive
Cache-Control: public, max-age=0, no-cache
X-Frame-Options: DENY
Strict-Transport-Security: max-age=604800

{
  "Q5kkPCShlRQ": "https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417",
  "keyChange": "https://acme-v02.api.letsencrypt.org/acme/key-change",
  "meta": {
    "caaIdentities": [
      "letsencrypt.org"
    ],
    "termsOfService": "https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf",
    "website": "https://letsencrypt.org"
  },
  "newAccount": "https://acme-v02.api.letsencrypt.org/acme/new-acct",
  "newNonce": "https://acme-v02.api.letsencrypt.org/acme/new-nonce",
  "newOrder": "https://acme-v02.api.letsencrypt.org/acme/new-order",
  "renewalInfo": "https://acme-v02.api.letsencrypt.org/draft-ietf-acme-ari-01/renewalInfo/",
  "revokeCert": "https://acme-v02.api.letsencrypt.org/acme/revoke-cert"
}
2023-10-12 17:11:49,201:DEBUG:certbot._internal.storage:Should renew, less than 30 days before certificate expiry 2023-10-10 11:53:51 UTC.
2023-10-12 17:11:49,201:INFO:certbot._internal.renewal:Certificate is due for renewal, auto-renewing...
2023-10-12 17:11:49,202:DEBUG:certbot._internal.display.obj:Notifying user: Renewing an existing certificate for *.mydomain.com
2023-10-12 17:11:49,223:DEBUG:acme.client:Requesting fresh nonce
2023-10-12 17:11:49,223:DEBUG:acme.client:Sending HEAD request to https://acme-v02.api.letsencrypt.org/acme/new-nonce.
2023-10-12 17:11:49,381:DEBUG:urllib3.connectionpool:https://acme-v02.api.letsencrypt.org:443 "HEAD /acme/new-nonce HTTP/1.1" 200 0
2023-10-12 17:11:49,382:DEBUG:acme.client:Received response:
HTTP 200
Server: nginx
Date: Thu, 12 Oct 2023 17:11:49 GMT
Connection: keep-alive
Cache-Control: public, max-age=0, no-cache
Link: <https://acme-v02.api.letsencrypt.org/directory>;rel="index"
Replay-Nonce: _s_5u1NQesnT8oZjPBpqAaEhMw2v6CydHCwhnmR5XInLyyHRIPE
X-Frame-Options: DENY
Strict-Transport-Security: max-age=604800


2023-10-12 17:11:49,382:DEBUG:acme.client:Storing nonce: _s_5u1NQesnT8oZjPBpqAaEhMw2v6CydHCwhnmR5XInLyyHRIPE
2023-10-12 17:11:49,383:DEBUG:acme.client:JWS payload:
b'{\n  "identifiers": [\n    {\n      "type": "dns",\n      "value": "*.mydomain.com"\n    }\n  ]\n}'
2023-10-12 17:11:49,386:DEBUG:acme.client:Sending POST request to https://acme-v02.api.letsencrypt.org/acme/new-order:
{
  "protected": "eyJhbGciOiAiUlMyNTYiLCAia2lkIjogImh0dHBzOi8vYWNtZS12MDIuYXBpLmxldHNlbmNyeXB0Lm9yZy9hY21lL2FjY3QvNzI4MDE1OTk3IiwgIm5vbmNlIjogIl9zXzV1MU5RZXNuVDhvWmpQQnBxQWFFaE13MnY2Q3lkSEN3aG5tUjVYSW5MeXlIUklQRSIsICJ1cmwiOiAiaHR0cHM6Ly9hY21lLXYwMi5hcGkubGV0c2VuY3J5cHQub3JnL2FjbWUvbmV3LW9yZGVyIn0",
  "signature": "Jj0Sp2hzhdI2hDnBEFcqvMhhIf0mPsH89YUFw-7Se-rglCtsxrxrituJzMpx2ES2FiMiCJYu-f8DKtVxM2hYSbxpho0Uhn0eWtmIUjkHZvZZs54cYQR7CLP2hZ37mn9eq-Jlb1GFLPTEqbgIUhel90RM09mLPEa2O-sq0S9RamdDlAHGqd3EpHGUQG4VqMxXYD7SGRMkQA2fLMJgoh1wdrWOKKfU_UbdXF-qG4DyBWSjSAc2HzXMRSRoc-6xIcXO2mjFz4jG9mA3fFT7WCCKf2MzPpqyeWyIBY1a7nK0VkQrvqjoa3WsHXx0XTMZUwUBST2raKGKUdnMwu4R8dqx4g",
  "payload": "ewogICJpZGVudGlmaWVycyI6IFsKICAgIHsKICAgICAgInR5cGUiOiAiZG5zIiwKICAgICAgInZhbHVlIjogIioubWd1eWFyZC5jb20iCiAgICB9CiAgXQp9"
}
2023-10-12 17:11:49,565:DEBUG:urllib3.connectionpool:https://acme-v02.api.letsencrypt.org:443 "POST /acme/new-order HTTP/1.1" 201 338
2023-10-12 17:11:49,566:DEBUG:acme.client:Received response:
HTTP 201
Server: nginx
Date: Thu, 12 Oct 2023 17:11:49 GMT
Content-Type: application/json
Content-Length: 338
Connection: keep-alive
Boulder-Requester: 728015997
Cache-Control: public, max-age=0, no-cache
Link: <https://acme-v02.api.letsencrypt.org/directory>;rel="index"
Location: https://acme-v02.api.letsencrypt.org/acme/order/728015997/214563998906
Replay-Nonce: _s_5u1NQdwW67X0xzS5_dSAlKHRVyVeyJKM_Zg4ZROl40Auts9w
X-Frame-Options: DENY
Strict-Transport-Security: max-age=604800

{
  "status": "pending",
  "expires": "2023-10-19T11:11:26Z",
  "identifiers": [
    {
      "type": "dns",
      "value": "*.mydomain.com"
    }
  ],
  "authorizations": [
    "https://acme-v02.api.letsencrypt.org/acme/authz-v3/273135072886"
  ],
  "finalize": "https://acme-v02.api.letsencrypt.org/acme/finalize/728015997/214563998906"
}
2023-10-12 17:11:49,567:DEBUG:acme.client:Storing nonce: _s_5u1NQdwW67X0xzS5_dSAlKHRVyVeyJKM_Zg4ZROl40Auts9w
2023-10-12 17:11:49,568:DEBUG:acme.client:JWS payload:
b''
2023-10-12 17:11:49,571:DEBUG:acme.client:Sending POST request to https://acme-v02.api.letsencrypt.org/acme/authz-v3/273135072886:
{
  "protected": "eyJhbGciOiAiUlMyNTYiLCAia2lkIjogImh0dHBzOi8vYWNtZS12MDIuYXBpLmxldHNlbmNyeXB0Lm9yZy9hY21lL2FjY3QvNzI4MDE1OTk3IiwgIm5vbmNlIjogIl9zXzV1MU5RZHdXNjdYMHh6UzVfZFNBbEtIUlZ5VmV5SktNX1pnNFpST2w0MEF1dHM5dyIsICJ1cmwiOiAiaHR0cHM6Ly9hY21lLXYwMi5hcGkubGV0c2VuY3J5cHQub3JnL2FjbWUvYXV0aHotdjMvMjczMTM1MDcyODg2In0",
  "signature": "Xd5zPjUSbV039jIfs_bOBd2bajp8iiAQoKaRWLzZHkSMvbnTRliGzedTaQo9b01qiI-J1USTkbqdlXq15RujAhh-CdmD70qCVGup8-K5R-gfWsCBl5DwmUdA5ytGmRhbQCLSZt40OaNvAlfD3HwLeeAwg43yR7UcHfz1Mk-Pa4Lc-70TxaBImNlVeMM5G4UbR0Bb03o10OW8_krdXPz-NYssLiIDV9T-_sfP7zB_D2CJ54o2zHx5oeM3DWnHCQCprcbPlGlgi4IVzr3hhhq_AkpxI6IIvl_F9ziKiYI2-DecfPbSVt9sczs5wrb4wwOx7kOKWTVkwwZjD_46JAVjlg",
  "payload": ""
}
2023-10-12 17:11:49,732:DEBUG:urllib3.connectionpool:https://acme-v02.api.letsencrypt.org:443 "POST /acme/authz-v3/273135072886 HTTP/1.1" 200 385
2023-10-12 17:11:49,733:DEBUG:acme.client:Received response:
HTTP 200
Server: nginx
Date: Thu, 12 Oct 2023 17:11:49 GMT
Content-Type: application/json
Content-Length: 385
Connection: keep-alive
Boulder-Requester: 728015997
Cache-Control: public, max-age=0, no-cache
Link: <https://acme-v02.api.letsencrypt.org/directory>;rel="index"
Replay-Nonce: _s_5u1NQSMtSKKLPhg0YW4NUXu-3WtIhNW_K3-1HP9ItVKD_ItQ
X-Frame-Options: DENY
Strict-Transport-Security: max-age=604800

{
  "identifier": {
    "type": "dns",
    "value": "mydomain.com"
  },
  "status": "pending",
  "expires": "2023-10-19T11:11:26Z",
  "challenges": [
    {
      "type": "dns-01",
      "status": "pending",
      "url": "https://acme-v02.api.letsencrypt.org/acme/chall-v3/273135072886/g5IbYA",
      "token": "glIZphzibloH4KOTCCnIEVniRVcNdyghsHABrcOhIM8"
    }
  ],
  "wildcard": true
}
2023-10-12 17:11:49,734:DEBUG:acme.client:Storing nonce: _s_5u1NQSMtSKKLPhg0YW4NUXu-3WtIhNW_K3-1HP9ItVKD_ItQ
2023-10-12 17:11:49,734:INFO:certbot._internal.auth_handler:Performing the following challenges:
2023-10-12 17:11:49,735:INFO:certbot._internal.auth_handler:dns-01 challenge for mydomain.com
2023-10-12 17:11:49,786:DEBUG:filelock:Attempting to acquire lock 281473097129776 on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:49,787:DEBUG:filelock:Lock 281473097129776 acquired on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:49,788:DEBUG:filelock:Attempting to acquire lock 281473097131936 on /root/.lexicon_tld_set/urls/62bf135d1c2f3d4db4228b9ecaf507a2.tldextract.json.lock
2023-10-12 17:11:49,788:DEBUG:filelock:Lock 281473097131936 acquired on /root/.lexicon_tld_set/urls/62bf135d1c2f3d4db4228b9ecaf507a2.tldextract.json.lock
2023-10-12 17:11:49,789:DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): publicsuffix.org:443
2023-10-12 17:11:50,376:DEBUG:urllib3.connectionpool:https://publicsuffix.org:443 "GET /list/public_suffix_list.dat HTTP/1.1" 200 81964
2023-10-12 17:11:50,404:DEBUG:filelock:Attempting to release lock 281473097131936 on /root/.lexicon_tld_set/urls/62bf135d1c2f3d4db4228b9ecaf507a2.tldextract.json.lock
2023-10-12 17:11:50,405:DEBUG:filelock:Lock 281473097131936 released on /root/.lexicon_tld_set/urls/62bf135d1c2f3d4db4228b9ecaf507a2.tldextract.json.lock
2023-10-12 17:11:50,421:DEBUG:filelock:Attempting to release lock 281473097129776 on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:50,422:DEBUG:filelock:Lock 281473097129776 released on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:50,458:DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): eu.api.ovh.com:443
2023-10-12 17:11:50,730:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/auth/time HTTP/1.1" 200 10
2023-10-12 17:11:50,779:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/domain/zone/ HTTP/1.1" 200 None
2023-10-12 17:11:50,901:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/domain/zone/mydomain.com/status HTTP/1.1" 200 None
2023-10-12 17:11:50,942:DEBUG:filelock:Attempting to acquire lock 281473084944640 on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:50,943:DEBUG:filelock:Lock 281473084944640 acquired on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:50,944:DEBUG:filelock:Attempting to release lock 281473084944640 on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:50,944:DEBUG:filelock:Lock 281473084944640 released on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:50,961:DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): eu.api.ovh.com:443
2023-10-12 17:11:51,229:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/auth/time HTTP/1.1" 200 10
2023-10-12 17:11:51,264:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/domain/zone/ HTTP/1.1" 200 None
2023-10-12 17:11:51,339:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/domain/zone/mydomain.com/status HTTP/1.1" 200 None
2023-10-12 17:11:51,394:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/domain/zone/mydomain.com/record?fieldType=TXT&subDomain=_acme-challenge HTTP/1.1" 200 2
2023-10-12 17:11:51,396:DEBUG:lexicon._private.providers.ovh:list_records: []
2023-10-12 17:11:51,544:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "POST /1.0/domain/zone/mydomain.com/record HTTP/1.1" 200 None
2023-10-12 17:11:51,652:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "POST /1.0/domain/zone/mydomain.com/refresh HTTP/1.1" 204 0
2023-10-12 17:11:51,654:DEBUG:certbot.plugins.dns_common_lexicon:Encountered error adding TXT record: Expecting value: line 1 column 1 (char 0)
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 971, in json
    return complexjson.loads(self.text, **kwargs)
  File "/usr/local/lib/python3.10/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python3.10/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/lib/python3.10/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/certbot/src/certbot/certbot/plugins/dns_common_lexicon.py", line 221, in _perform
    operations.create_record(rtype='TXT', name=validation_name, content=validation)
  File "/usr/local/lib/python3.10/site-packages/lexicon/client.py", line 34, in create_record
    return self.provider.create_record(rtype, name, content)
  File "/usr/local/lib/python3.10/site-packages/lexicon/_private/providers/ovh.py", line 129, in create_record
    self._post(f"/domain/zone/{domain}/refresh")
  File "/usr/local/lib/python3.10/site-packages/lexicon/interfaces.py", line 168, in _post
    return self._request("POST", url, data=data, query_params=query_params)
  File "/usr/local/lib/python3.10/site-packages/lexicon/_private/providers/ovh.py", line 260, in _request
    return result.json()
  File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 975, in json
    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
2023-10-12 17:11:51,658:DEBUG:certbot._internal.error_handler:Encountered exception:
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 971, in json
    return complexjson.loads(self.text, **kwargs)
  File "/usr/local/lib/python3.10/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python3.10/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/lib/python3.10/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/certbot/src/certbot/certbot/plugins/dns_common_lexicon.py", line 221, in _perform
    operations.create_record(rtype='TXT', name=validation_name, content=validation)
  File "/usr/local/lib/python3.10/site-packages/lexicon/client.py", line 34, in create_record
    return self.provider.create_record(rtype, name, content)
  File "/usr/local/lib/python3.10/site-packages/lexicon/_private/providers/ovh.py", line 129, in create_record
    self._post(f"/domain/zone/{domain}/refresh")
  File "/usr/local/lib/python3.10/site-packages/lexicon/interfaces.py", line 168, in _post
    return self._request("POST", url, data=data, query_params=query_params)
  File "/usr/local/lib/python3.10/site-packages/lexicon/_private/providers/ovh.py", line 260, in _request
    return result.json()
  File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 975, in json
    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/certbot/src/certbot/certbot/_internal/auth_handler.py", line 88, in handle_authorizations
    resps = self.auth.perform(achalls)
  File "/opt/certbot/src/certbot/certbot/plugins/dns_common.py", line 76, in perform
    self._perform(domain, validation_domain_name, validation)
  File "/opt/certbot/src/certbot/certbot/plugins/dns_common_lexicon.py", line 224, in _perform
    raise errors.PluginError('Error adding TXT record: {0}'.format(e))
certbot.errors.PluginError: Error adding TXT record: Expecting value: line 1 column 1 (char 0)

2023-10-12 17:11:51,659:DEBUG:certbot._internal.error_handler:Calling registered functions
2023-10-12 17:11:51,659:INFO:certbot._internal.auth_handler:Cleaning up challenges
2023-10-12 17:11:51,695:DEBUG:filelock:Attempting to acquire lock 281473082809680 on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:51,696:DEBUG:filelock:Lock 281473082809680 acquired on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:51,697:DEBUG:filelock:Attempting to release lock 281473082809680 on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:51,697:DEBUG:filelock:Lock 281473082809680 released on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:51,720:DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): eu.api.ovh.com:443
2023-10-12 17:11:52,034:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/auth/time HTTP/1.1" 200 10
2023-10-12 17:11:52,110:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/domain/zone/ HTTP/1.1" 200 None
2023-10-12 17:11:52,199:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/domain/zone/mydomain.com/status HTTP/1.1" 200 None
2023-10-12 17:11:52,242:DEBUG:filelock:Attempting to acquire lock 281473085303072 on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:52,243:DEBUG:filelock:Lock 281473085303072 acquired on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:52,244:DEBUG:filelock:Attempting to release lock 281473085303072 on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:52,244:DEBUG:filelock:Lock 281473085303072 released on /root/.lexicon_tld_set/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock
2023-10-12 17:11:52,261:DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): eu.api.ovh.com:443
2023-10-12 17:11:52,559:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/auth/time HTTP/1.1" 200 10
2023-10-12 17:11:52,618:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/domain/zone/ HTTP/1.1" 200 None
2023-10-12 17:11:52,689:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/domain/zone/mydomain.com/status HTTP/1.1" 200 None
2023-10-12 17:11:52,759:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/domain/zone/mydomain.com/record?fieldType=TXT&subDomain=_acme-challenge HTTP/1.1" 200 12
2023-10-12 17:11:52,812:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "GET /1.0/domain/zone/mydomain.com/record/5288946926 HTTP/1.1" 200 None
2023-10-12 17:11:52,813:DEBUG:lexicon._private.providers.ovh:list_records: [{'type': 'TXT', 'name': '_acme-challenge.mydomain.com', 'ttl': 60, 'content': 'XUBy2LmYnK0XEIf5m3C55irRFyXmqQioIy_YcxCyy6E', 'id': 5288946926}]
2023-10-12 17:11:52,814:DEBUG:lexicon._private.providers.ovh:delete_records: [5288946926]
2023-10-12 17:11:52,936:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "DELETE /1.0/domain/zone/mydomain.com/record/5288946926 HTTP/1.1" 200 4
2023-10-12 17:11:53,031:DEBUG:urllib3.connectionpool:https://eu.api.ovh.com:443 "POST /1.0/domain/zone/mydomain.com/refresh HTTP/1.1" 204 0
2023-10-12 17:11:53,033:DEBUG:certbot.plugins.dns_common_lexicon:Encountered error deleting TXT record: Expecting value: line 1 column 1 (char 0)
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 971, in json
    return complexjson.loads(self.text, **kwargs)
  File "/usr/local/lib/python3.10/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python3.10/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/lib/python3.10/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/certbot/src/certbot/certbot/plugins/dns_common_lexicon.py", line 236, in _cleanup
    operations.delete_record(rtype='TXT', name=validation_name, content=validation)
  File "/usr/local/lib/python3.10/site-packages/lexicon/client.py", line 73, in delete_record
    return self.provider.delete_record(identifier, rtype, name, content)
  File "/usr/local/lib/python3.10/site-packages/lexicon/_private/providers/ovh.py", line 210, in delete_record
    self._post(f"/domain/zone/{domain}/refresh")
  File "/usr/local/lib/python3.10/site-packages/lexicon/interfaces.py", line 168, in _post
    return self._request("POST", url, data=data, query_params=query_params)
  File "/usr/local/lib/python3.10/site-packages/lexicon/_private/providers/ovh.py", line 260, in _request
    return result.json()
  File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 975, in json
    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
2023-10-12 17:11:53,037:DEBUG:certbot._internal.log:Exiting abnormally:
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 971, in json
    return complexjson.loads(self.text, **kwargs)
  File "/usr/local/lib/python3.10/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python3.10/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/lib/python3.10/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/certbot/src/certbot/certbot/plugins/dns_common_lexicon.py", line 221, in _perform
    operations.create_record(rtype='TXT', name=validation_name, content=validation)
  File "/usr/local/lib/python3.10/site-packages/lexicon/client.py", line 34, in create_record
    return self.provider.create_record(rtype, name, content)
  File "/usr/local/lib/python3.10/site-packages/lexicon/_private/providers/ovh.py", line 129, in create_record
    self._post(f"/domain/zone/{domain}/refresh")
  File "/usr/local/lib/python3.10/site-packages/lexicon/interfaces.py", line 168, in _post
    return self._request("POST", url, data=data, query_params=query_params)
  File "/usr/local/lib/python3.10/site-packages/lexicon/_private/providers/ovh.py", line 260, in _request
    return result.json()
  File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 975, in json
    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/bin/certbot", line 33, in <module>
    sys.exit(load_entry_point('certbot', 'console_scripts', 'certbot')())
  File "/opt/certbot/src/certbot/certbot/main.py", line 19, in main
    return internal_main.main(cli_args)
  File "/opt/certbot/src/certbot/certbot/_internal/main.py", line 1873, in main
    return config.func(config, plugins)
  File "/opt/certbot/src/certbot/certbot/_internal/main.py", line 1600, in certonly
    lineage = _get_and_save_cert(le_client, config, domains, certname, lineage)
  File "/opt/certbot/src/certbot/certbot/_internal/main.py", line 131, in _get_and_save_cert
    renewal.renew_cert(config, domains, le_client, lineage)
  File "/opt/certbot/src/certbot/certbot/_internal/renewal.py", line 396, in renew_cert
    new_cert, new_chain, new_key, _ = le_client.obtain_certificate(domains, new_key)
  File "/opt/certbot/src/certbot/certbot/_internal/client.py", line 428, in obtain_certificate
    orderr = self._get_order_and_authorizations(csr.data, self.config.allow_subset_of_names)
  File "/opt/certbot/src/certbot/certbot/_internal/client.py", line 496, in _get_order_and_authorizations
    authzr = self.auth_handler.handle_authorizations(orderr, self.config, best_effort)
  File "/opt/certbot/src/certbot/certbot/_internal/auth_handler.py", line 88, in handle_authorizations
    resps = self.auth.perform(achalls)
  File "/opt/certbot/src/certbot/certbot/plugins/dns_common.py", line 76, in perform
    self._perform(domain, validation_domain_name, validation)
  File "/opt/certbot/src/certbot/certbot/plugins/dns_common_lexicon.py", line 224, in _perform
    raise errors.PluginError('Error adding TXT record: {0}'.format(e))
certbot.errors.PluginError: Error adding TXT record: Expecting value: line 1 column 1 (char 0)
2023-10-12 17:11:53,039:ERROR:certbot._internal.log:Error adding TXT record: Expecting value: line 1 column 1 (char 0)
```



Discussion / hints:
This looks like a bug in the third-party DNS library we use, [lexicon](https://github.com/AnalogJ/lexicon), so it might be worth opening a ticket there. I looked into it briefly, though, and [ovh's docs](
https://api.ovh.com/console/#/domain/zone/%7BzoneName%7D/refresh~POST) do seem to say that the request causing this exception should return "void", i.e. an empty HTTP body, so it seems lexicon's handling that as a JSON body might be incorrect.
Thanks. Issue was created.
For information and if this can help, in 2.5.0 it's works but not in 2.6.0

Fix patch:
diff --git a/certbot-ci/setup.py b/certbot-ci/setup.py
index 2cb8308c115..81feeb7cfef 100644
--- a/certbot-ci/setup.py
+++ b/certbot-ci/setup.py
@@ -21,7 +21,7 @@
     'pytz>=2019.3',
     'requests',
     'setuptools',
-    'types-python-dateutil'
+    'types-python-dateutil',
 ]
 
 setup(
diff --git a/certbot-dns-ovh/setup.py b/certbot-dns-ovh/setup.py
index e4c615f3f0e..e3fe41d8287 100644
--- a/certbot-dns-ovh/setup.py
+++ b/certbot-dns-ovh/setup.py
@@ -7,7 +7,7 @@
 version = '2.8.0.dev0'
 
 install_requires = [
-    'dns-lexicon>=3.14.1',
+    'dns-lexicon>=3.15.1',
     'setuptools>=41.6.0',
 ]
 
diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md
index 92ceba3fb3b..900948fc635 100644
--- a/certbot/CHANGELOG.md
+++ b/certbot/CHANGELOG.md
@@ -14,6 +14,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
 
 ### Fixed
 
+* `certbot-dns-ovh` plugin now requires `lexicon>=3.15.1` to ensure a consistent behavior with OVH APIs.
 * Fixed a bug where argument sources weren't correctly detected in abbreviated
   arguments, short arguments, and some other circumstances
 
diff --git a/tools/oldest_constraints.txt b/tools/oldest_constraints.txt
index d667873d48c..2f09901a159 100644
--- a/tools/oldest_constraints.txt
+++ b/tools/oldest_constraints.txt
@@ -20,7 +20,7 @@ cython==0.29.36 ; python_version >= "3.8" and python_version < "3.9"
 dill==0.3.7 ; python_version >= "3.8" and python_version < "3.9"
 distlib==0.3.7 ; python_version >= "3.8" and python_version < "3.9"
 distro==1.0.1 ; python_version >= "3.8" and python_version < "3.9"
-dns-lexicon==3.14.1 ; python_version >= "3.8" and python_version < "3.9"
+dns-lexicon==3.15.1 ; python_version >= "3.8" and python_version < "3.9"
 dnspython==1.15.0 ; python_version >= "3.8" and python_version < "3.9"
 exceptiongroup==1.1.3 ; python_version >= "3.8" and python_version < "3.9"
 execnet==2.0.2 ; python_version >= "3.8" and python_version < "3.9"
@@ -41,7 +41,7 @@ josepy==1.13.0 ; python_version >= "3.8" and python_version < "3.9"
 logger==1.4 ; python_version >= "3.8" and python_version < "3.9"
 mccabe==0.7.0 ; python_version >= "3.8" and python_version < "3.9"
 mypy-extensions==1.0.0 ; python_version >= "3.8" and python_version < "3.9"
-mypy==1.5.1 ; python_version >= "3.8" and python_version < "3.9"
+mypy==1.6.0 ; python_version >= "3.8" and python_version < "3.9"
 ndg-httpsclient==0.3.2 ; python_version >= "3.8" and python_version < "3.9"
 oauth2client==4.1.3 ; python_version >= "3.8" and python_version < "3.9"
 packaging==23.2 ; python_version >= "3.8" and python_version < "3.9"
@@ -57,6 +57,7 @@ pyasn1==0.4.8 ; python_version >= "3.8" and python_version < "3.9"
 pycparser==2.14 ; python_version >= "3.8" and python_version < "3.9"
 pylint==3.0.1 ; python_version >= "3.8" and python_version < "3.9"
 pyopenssl==17.5.0 ; python_version >= "3.8" and python_version < "3.9"
+pyotp==2.9.0 ; python_version >= "3.8" and python_version < "3.9"
 pyparsing==2.2.1 ; python_version >= "3.8" and python_version < "3.9"
 pyrfc3339==1.0 ; python_version >= "3.8" and python_version < "3.9"
 pytest-cov==4.1.0 ; python_version >= "3.8" and python_version < "3.9"
@@ -75,7 +76,7 @@ s3transfer==0.3.7 ; python_version >= "3.8" and python_version < "3.9"
 setuptools==41.6.0 ; python_version >= "3.8" and python_version < "3.9"
 six==1.11.0 ; python_version >= "3.8" and python_version < "3.9"
 soupsieve==2.5 ; python_version >= "3.8" and python_version < "3.9"
-tldextract==3.6.0 ; python_version >= "3.8" and python_version < "3.9"
+tldextract==5.0.0 ; python_version >= "3.8" and python_version < "3.9"
 tomli==2.0.1 ; python_version >= "3.8" and python_version < "3.9"
 tomlkit==0.12.1 ; python_version >= "3.8" and python_version < "3.9"
 tox==1.9.2 ; python_version >= "3.8" and python_version < "3.9"
diff --git a/tools/pinning/oldest/pyproject.toml b/tools/pinning/oldest/pyproject.toml
index 302014ae595..1a4d7d71f38 100644
--- a/tools/pinning/oldest/pyproject.toml
+++ b/tools/pinning/oldest/pyproject.toml
@@ -54,7 +54,7 @@ cloudflare = "1.5.1"
 configobj = "5.0.6"
 cryptography = "3.2.1"
 distro = "1.0.1"
-dns-lexicon = "3.14.1"
+dns-lexicon = "3.15.1"
 dnspython = "1.15.0"
 funcsigs = "0.4"
 google-api-python-client = "1.6.5"
diff --git a/tools/requirements.txt b/tools/requirements.txt
index af906a4ba21..1ed0ca0ee78 100644
--- a/tools/requirements.txt
+++ b/tools/requirements.txt
@@ -17,8 +17,8 @@ babel==2.13.0 ; python_version >= "3.8" and python_version < "4.0"
 backcall==0.2.0 ; python_version >= "3.8" and python_version < "4.0"
 bcrypt==4.0.1 ; python_version >= "3.8" and python_version < "4.0"
 beautifulsoup4==4.12.2 ; python_version >= "3.8" and python_version < "4.0"
-boto3==1.28.62 ; python_version >= "3.8" and python_version < "4.0"
-botocore==1.31.62 ; python_version >= "3.8" and python_version < "4.0"
+boto3==1.28.63 ; python_version >= "3.8" and python_version < "4.0"
+botocore==1.31.63 ; python_version >= "3.8" and python_version < "4.0"
 cachecontrol==0.12.14 ; python_version >= "3.8" and python_version < "4.0"
 cachetools==5.3.1 ; python_version >= "3.8" and python_version < "4.0"
 cachy==0.3.0 ; python_version >= "3.8" and python_version < "4.0"
@@ -39,7 +39,7 @@ deprecated==1.2.14 ; python_version >= "3.8" and python_version < "4.0"
 dill==0.3.7 ; python_version >= "3.8" and python_version < "4.0"
 distlib==0.3.7 ; python_version >= "3.8" and python_version < "4.0"
 distro==1.8.0 ; python_version >= "3.8" and python_version < "4.0"
-dns-lexicon==3.15.0 ; python_version >= "3.8" and python_version < "4.0"
+dns-lexicon==3.15.1 ; python_version >= "3.8" and python_version < "4.0"
 dnspython==2.4.2 ; python_version >= "3.8" and python_version < "4.0"
 docutils==0.18.1 ; python_version >= "3.8" and python_version < "4.0"
 dulwich==0.20.50 ; python_version >= "3.8" and python_version < "4.0"
@@ -49,10 +49,10 @@ executing==2.0.0 ; python_version >= "3.8" and python_version < "4.0"
 fabric==3.2.2 ; python_version >= "3.8" and python_version < "4.0"
 filelock==3.12.4 ; python_version >= "3.8" and python_version < "4.0"
 google-api-core==2.12.0 ; python_version >= "3.8" and python_version < "4.0"
-google-api-python-client==2.102.0 ; python_version >= "3.8" and python_version < "4.0"
+google-api-python-client==2.103.0 ; python_version >= "3.8" and python_version < "4.0"
 google-auth-httplib2==0.1.1 ; python_version >= "3.8" and python_version < "4.0"
 google-auth==2.23.3 ; python_version >= "3.8" and python_version < "4.0"
-googleapis-common-protos==1.60.0 ; python_version >= "3.8" and python_version < "4.0"
+googleapis-common-protos==1.61.0 ; python_version >= "3.8" and python_version < "4.0"
 html5lib==1.1 ; python_version >= "3.8" and python_version < "4.0"
 httplib2==0.22.0 ; python_version >= "3.8" and python_version < "4.0"
 idna==3.4 ; python_version >= "3.8" and python_version < "4.0"
@@ -87,7 +87,7 @@ more-itertools==10.1.0 ; python_version >= "3.8" and python_version < "4.0"
 msgpack==1.0.7 ; python_version >= "3.8" and python_version < "4.0"
 msrest==0.7.1 ; python_version >= "3.8" and python_version < "4.0"
 mypy-extensions==1.0.0 ; python_version >= "3.8" and python_version < "4.0"
-mypy==1.5.1 ; python_version >= "3.8" and python_version < "4.0"
+mypy==1.6.0 ; python_version >= "3.8" and python_version < "4.0"
 nh3==0.2.14 ; python_version >= "3.8" and python_version < "4.0"
 oauthlib==3.2.2 ; python_version >= "3.8" and python_version < "4.0"
 packaging==23.2 ; python_version >= "3.8" and python_version < "4.0"
@@ -141,7 +141,7 @@ requests-toolbelt==0.9.1 ; python_version >= "3.8" and python_version < "4.0"
 requests==2.31.0 ; python_version >= "3.8" and python_version < "4.0"
 rfc3986==2.0.0 ; python_version >= "3.8" and python_version < "4.0"
 rich==13.6.0 ; python_version >= "3.8" and python_version < "4.0"
-rpds-py==0.10.4 ; python_version >= "3.8" and python_version < "4.0"
+rpds-py==0.10.6 ; python_version >= "3.8" and python_version < "4.0"
 rsa==4.9 ; python_version >= "3.8" and python_version < "4"
 s3transfer==0.7.0 ; python_version >= "3.8" and python_version < "4.0"
 secretstorage==3.3.3 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "linux"
@@ -162,7 +162,7 @@ sphinxcontrib-jsmath==1.0.1 ; python_version >= "3.8" and python_version < "4.0"
 sphinxcontrib-qthelp==1.0.3 ; python_version >= "3.8" and python_version < "4.0"
 sphinxcontrib-serializinghtml==1.1.5 ; python_version >= "3.8" and python_version < "4.0"
 stack-data==0.6.3 ; python_version >= "3.8" and python_version < "4.0"
-tldextract==3.6.0 ; python_version >= "3.8" and python_version < "4.0"
+tldextract==5.0.0 ; python_version >= "3.8" and python_version < "4.0"
 tomli==2.0.1 ; python_version >= "3.8" and python_full_version <= "3.11.0a6"
 tomlkit==0.12.1 ; python_version >= "3.8" and python_version < "4.0"
 tox==3.28.0 ; python_version >= "3.8" and python_version < "4.0"


Test patch:
diff --git a/certbot-ci/certbot_integration_tests/utils/misc.py b/certbot-ci/certbot_integration_tests/utils/misc.py
index 8260ccf5e58..dfeda4cda5b 100644
--- a/certbot-ci/certbot_integration_tests/utils/misc.py
+++ b/certbot-ci/certbot_integration_tests/utils/misc.py
@@ -52,10 +52,10 @@ def _suppress_x509_verification_warnings() -> None:
         urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
     except ImportError:
         # Handle old versions of request with vendorized urllib3
-        # pylint: disable=no-member
-        from requests.packages.urllib3.exceptions import InsecureRequestWarning
-        requests.packages.urllib3.disable_warnings(  # type: ignore[attr-defined]
-            InsecureRequestWarning)
+        # pylint: disable=no-member,line-too-long
+        from requests.packages.urllib3.exceptions import InsecureRequestWarning  # type: ignore[import-untyped]
+        requests.packages.urllib3.disable_warnings(InsecureRequestWarning)  # type: ignore[attr-defined]
+        # pylint: enable=no-member,line-too-long
 
 
 def check_until_timeout(url: str, attempts: int = 30) -> None: