When creating the records on a new instance, stalwart will create several records in a row one after another:
If there are too many requests in a row, porkbun throws a 503 error:
Failed to set DNS RRSet for mydomain.com./TXT: Failed to set DNS RRSet: API error: BadRequest {"status":"ERROR","message":"Edit error: We were unable to edit the DNS record.","code":"EDIT_ERROR_WE_WERE_UNABLE_TO_EDIT_THE_DNS_RECORD","requestId":""}; Failed to set DNS RRSet for autodiscover.mydomain.com./CNAME: Failed to set DNS RRSet: API error: HTTP 503: <html>\r\n<head><title>503 Service Temporarily Unavailable</title></head>\r\n<body>\r\n<center><h1>503 Service Temporarily Unavailable</h1></center>\r\n<hr><center>openresty</center>\r\n</body>\r\n</html>
There doesn’t seem to be any config option to have stalwart slow down inbetween requests.
Expected Behavior
Domain tasks either slows down to protect against rate limits.
Actual Behavior
The entire DNS management task fails.
Reproduction Steps
Configure stalwart to use porkbun on a fresh domain
Stalwart Version
v0.16.x
Installation Method
Binary (Linux)
Database Backend
PostgreSQL
Blob Storage
S3-compatible
Search Engine
Internal
Directory Backend
Internal
Additional Context
Reverse proxy via nginx
I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.
on
I have searched this support forum (open and closed topics) and confirm this is not a duplicate.
on
I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.
This is a confirmed gap in the current implementation. Looking at the source code and documentation, there is currently no per-request delay or throttling option in the DnsServer configuration for Porkbun (or any other provider). The DNS management task fires all set_rrset calls sequentially in a tight loop with no sleep between them, which is exactly the behavior you’re hitting.
The available DnsServer fields for Porkbun are:
timeout – per-request timeout (default 30s)
ttl – TTL on created records (default 5m)
pollingInterval – how often to check propagation (default 15s)
propagationTimeout – how long to wait for propagation (default 1m)
propagationDelay – initial delay before the first propagation check (useful for slow providers, but this is post-creation, not between API calls)
None of these introduce a delay between individual API calls, so there is no configuration-side workaround to throttle the burst toward Porkbun’s API. This is a code-level limitation in crates/services/src/task_manager/dns.rs.
A human staff member will need to evaluate adding an inter-request delay or retry-with-backoff logic for 429/503 responses from DNS providers.
I am using version v0.16.9, and the problem persists. I am experiencing an issue with Cloudflare.
The installation was performed using install.sh --fdb.
The backoff/retry fix did ship: 0.16.9 includes it and the Cloudflare path uses it (three attempts, exponential backoff, honoring Retry-After) on 429 and 503. So a plain rate-limit response should already be retried.
To see why it’s still failing for you I need the exact error. Can you paste the full “Failed to set DNS RRSet …” line from the log? If it’s a 429 or 503 something is off with the retry; if it’s a 4xx from Cloudflare (a validation, auth, or zone error) that’s a different problem and retrying
wouldn’t help. Also confirm the API token has DNS-edit scope on that zone.
The FoundationDB install flag isn’t related to this path.
Here is a snippet of the log.
If you need more detail, please let me know how I can provide it.
2026-06-20T17:32:31Z INFO Metrics collected (telemetry.metrics-collected) elapsed = 11ms
2026-06-20T17:33:22Z INFO DNS record created (dns.record-created) hostname = "_validation-persist.alpriva.cloud.", details = "alpriva.cloud", type = "TXT", value = ["letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/3447382586; policy=wildcard"]
2026-06-20T17:33:54Z INFO DNS record created (dns.record-created) hostname = "_ua-auto-config.alpriva.cloud.", details = "alpriva.cloud", type = "TXT", value = ["v=UAAC1; a=sha256; d=j24j9M/3HdsYGQS/IvrFnOXXjhnf3HNGvQoCBEm17+A="]
2026-06-20T17:34:27Z INFO DNS record created (dns.record-created) hostname = "_pop3s._tcp.alpriva.cloud.", details = "alpriva.cloud", type = "SRV", value = ["0 1 995 mail1dc1.prival.ru."]
2026-06-20T17:35:00Z INFO DNS record created (dns.record-created) hostname = "_caldavs._tcp.alpriva.cloud.", details = "alpriva.cloud", type = "SRV", value = ["0 1 443 mail1dc1.prival.ru."]
2026-06-20T17:35:31Z INFO DNS record created (dns.record-created) hostname = "alpriva.cloud.", details = "alpriva.cloud", type = "CAA", value = ["0 issue "letsencrypt.org;accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/3447382586"", "0 iodef "mailto:[email protected]""]
2026-06-20T17:35:32Z INFO DNS record created (dns.record-created) hostname = "_smtp._tls.alpriva.cloud.", details = "alpriva.cloud", type = "TXT", value = ["v=TLSRPTv1; rua=mailto:[email protected]"]
2026-06-20T17:36:36Z INFO DNS record created (dns.record-created) hostname = "ua-auto-config.alpriva.cloud.", details = "alpriva.cloud", type = "CNAME", value = ["mail1dc1.prival.ru."]
2026-06-20T17:37:07Z INFO DNS record created (dns.record-created) hostname = "alpriva.cloud.", details = "alpriva.cloud", type = "TXT", value = ["v=spf1 mx -all"]
2026-06-20T17:37:31Z INFO Task scheduled for future execution (task-manager.task-scheduled) due = 2026-06-20T17:42:30Z, id = "calculateMetrics"
2026-06-20T17:37:31Z INFO Metrics collected (telemetry.metrics-collected) elapsed = 7ms
2026-06-20T17:38:10Z INFO DNS record created (dns.record-created) hostname = "v1-ed25519-20260617._domainkey.alpriva.cloud.", details = "alpriva.cloud", type = "TXT", value = ["v=DKIM1; k=ed25519; h=sha256; p=ZebFUaz3ENWzm5MCwMzU6INHZYekHfyQGhgXZkB/6mA="]
2026-06-20T17:38:42Z INFO DNS record created (dns.record-created) hostname = "alpriva.cloud.", details = "alpriva.cloud", type = "MX", value = ["10 mail1dc1.prival.ru"]
2026-06-20T17:38:42Z WARN Task failed during processing (task-manager.task-failed) id = 313936946234605568, details = "DnsManagement", reason = "Failed to set DNS RRSet for v1-rsa-20260617._domainkey.alpriva.cloud./TXT: Failed to set DNS RRSet: API error: Failed to read response from https://api.cloudflare.com/client/v4/zones/754983de70dc207bbc5e0b47d32c938e/dns_records?name=v1-rsa-20260617._domainkey.alpriva.cloud&type=TXT&match=all&per_page=100: error decoding response body for url (https://api.cloudflare.com/client/v4/zones/754983de70dc207bbc5e0b47d32c938e/dns_records?name=v1-rsa-20260617._domainkey.alpriva.cloud&type=TXT&match=all&per_page=100); Failed to set DNS RRSet for autodiscover.alpriva.cloud./CNAME: Failed to set DNS RRSet: API error: Failed to read response from https://api.cloudflare.com/client/v4/zones/754983de70dc207bbc5e0b47d32c938e/dns_records?name=autodiscover.alpriva.cloud&type=CNAME&match=all&per_page=100: error decoding response body for url (https://api.cloudflare.com/client/v4/zones/754983de70dc207bbc5e0b47d32c938e/dns_records?name=autodiscover.alpriva.cloud&type=CNAME&match=all&per_page=100); Failed to set DNS RRSet for _imaps._tcp.alpriva.cloud./SRV: Failed to set DNS RRSet: API error: Failed to send request to https://api.cloudflare.com/client/v4/zones?name=alpriva.cloud: error sending request for url (https://api.cloudflare.com/client/v4/zones?name=alpriva.cloud); Failed to set DNS RRSet for mta-sts.alpriva.cloud./CNAME: Failed to set DNS RRSet: API error: Failed to send request to https://api.cloudflare.com/client/v4/zones?name=alpriva.cloud: error sending request for url (https://api.cloudflare.com/client/v4/zones?name=alpriva.cloud); Failed to set DNS RRSet for _mta-sts.alpriva.cloud./TXT: Failed to set DNS RRSet: API error: Failed to send request to https://api.cloudflare.com/client/v4/zones?name=alpriva.cloud: error sending request for url (https://api.cloudflare.com/client/v4/zones?name=alpriva.cloud); Failed to set DNS RRSet for autoconfig.alpriva.cloud./CNAME: Failed to set DNS RRSet: API error: Failed to send request to https://api.cloudflare.com/client/v4/zones/754983de70dc207bbc5e0b47d32c938e/dns_records: error sending request for url (https://api.cloudflare.com/client/v4/zones/754983de70dc207bbc5e0b47d32c938e/dns_records); Failed to set DNS RRSet for _dmarc.alpriva.cloud./TXT: Failed to set DNS RRSet: API error: Failed to send request to https://api.cloudflare.com/client/v4/zones?name=alpriva.cloud: error sending request for url (https://api.cloudflare.com/client/v4/zones?name=alpriva.cloud); Failed to set DNS RRSet for _submissions._tcp.alpriva.cloud./SRV: Failed to set DNS RRSet: API error: Failed to send request to https://api.cloudflare.com/client/v4/zones?name=alpriva.cloud: error sending request for url (https://api.cloudflare.com/client/v4/zones?name=alpriva.cloud); Failed to set DNS RRSet for _carddavs._tcp.alpriva.cloud./SRV: Failed to set DNS RRSet: API error: Failed to read response from https://api.cloudflare.com/client/v4/zones/754983de70dc207bbc5e0b47d32c938e/dns_records: error decoding response body for url (https://api.cloudflare.com/client/v4/zones/754983de70dc207bbc5e0b47d32c938e/dns_records); Failed to set DNS RRSet for _jmap._tcp.alpriva.cloud./SRV: Failed to set DNS RRSet: API error: Failed to send request to https://api.cloudflare.com/client/v4/zones/754983de70dc207bbc5e0b47d32c938e/dns_records: error sending request for url (https://api.cloudflare.com/client/v4/zones/754983de70dc207bbc5e0b47d32c938e/dns_records)"
The backoff/retry fix is in 0.16.9 and working, but it only kicks in on 429 and 503 rate-limit responses (three attempts, exponential backoff, honoring Retry-After). The errors in your log are a different category, “error sending request” means the request never reached Cloudflare at all (connection refused/reset, DNS resolution failure, or a timeout), and “error decoding response body” means a response started but was cut off mid-transfer.
Neither is a 429/503, so the rate-limit retry path correctly doesn’t apply; retrying wouldn’t help because nothing is being rate limited.
This points at outbound connectivity from the server host to api.cloudflare.com on 443: an egress firewall/NAT, local DNS resolution of that hostname, MTU/proxy interference, or a flaky link. The nginx reverse proxy in front of Stalwart isn’t involved since these are outbound API calls.
Can you run a direct request to the Cloudflare API from the server host (for example curl -v to https://api.cloudflare.com/client/v4/zones) and see whether it’s intermittently failing the same way? Also confirm the API token has DNS-edit scope on that zone, though that would show as a 4xx rather than these transport errors.
I have thoroughly debugged the Failed to set DNS RRSet (transport-level) errors. The issue is strictly isolated to Stalwart’s internal HTTP client (likely HTTP/2 multiplexing/connection pooling behavior in reqwest/hyper when hitting Cloudflare API edge nodes).
Environment & Tests performed:
Dedicated VM with a direct public IPv4 (No NAT/Conntrack exhaustion).
Disabled IPv6 completely via sysctl (to rule out IPv6 blackholing).
Hardcoded api.cloudflare.com to its IPv4 address in /etc/hosts (to rule out local DNS resolution timeouts).
Lowered interface MTU to 1360 (to rule out packet fragmentation drops).
Reproduction: Running a bash script that fires 20 concurrent curl requests to the exact same Cloudflare API endpoints (with the real Auth token and JSON payloads) succeeds 100% of the time with 0.3s latency.
Stalwart still fails under these exact conditions with error decoding response body and error sending request. Since concurrent curl works flawlessly on the same machine, the OS/Network is fine. Stalwart’s async client seems to be mishandling HTTP/2 multiplexing bursts, causing Cloudflare to reset the connection/streams.