Issue Description
Automatic DNS management via the INWX DnsServer provider fails when the zone already contains DNS records whose INWX API returns string record IDs (IDs exceeding the former 32-bit integer range).
Stalwart uses the dns-update crate (InwxProvider in src/providers/inwx.rs). When updating an RRSet, the provider calls nameserver.info and deserializes record[].id as i64. INWX now returns these IDs as JSON strings, which causes deserialization to fail before any create/update/delete can complete.
This breaks DnsManagement tasks and prevents Stalwart from publishing ACME-related TXT records (_validation-persist, _acme-challenge, apex SPF/DMARC, etc.) on domains with existing INWX records.
The same INWX API change was fixed elsewhere (lego ≥ 4.29, goinwx, Traefik 3.6.4); Stalwart’s INWX port appears to predate that change.
Expected Behavior
DnsManagementshould sync DNS records to INWX via the configuredDnsServer(@type: Inwx).set_rrset/add_to_rrsetshould read existing records withnameserver.info, reconcile the RRSet, and create/update/delete as needed.- ACME with automatic DNS (
Dns01/DnsPersist01) should be able to publish challenge TXT records.
Actual Behavior
DnsManagement fails when touching owners that already have TXT records in INWX (apex SPF/DKIM, subdomains, etc.). New records on previously empty owners may succeed (e.g. first SPF on mail.example.com), but any operation that must list existing records fails.
WebUI / task failure reason:
Failed to set DNS RRSet for example.com./TXT: Failed to set DNS RRSet: API error: Failed to parse INWX nameserver.info: invalid type: string "2377221647", expected i64
Reproduction Steps
- Use a domain on INWX with existing DNS records (any type; TXT at apex is enough — e.g. SPF/DKIM from a mail relay).
- Stalwart v0.16.x, native install (or Docker).
- Settings → Network → DNS → DNS Providers → create
InwxDnsServer(production API,sandbox: false). - Management → Domains → Domains → enable DNS management: Automatic with that provider.
- Management → Tasks → New Task → DNS management for the domain.
- Observe task failure with
Failed to parse INWX nameserver.info: invalid type: string "…", expected i64.
Minimal repro without Stalwart: call INWX nameserver.info for a name with existing records; response contains "id": "2377221647" (string). Current NameserverRecord { id: i64 } in dns-update cannot deserialize it.
Relevant Log Output
2026-06-05T09:44:27Z DEBUG DNS record lookup failed (dns.record-lookup-failed) hostname = “…”, details = “…”, type = “TXT”, reason = “DNS provider failed to list RRSet: API error: Failed to parse INWX nameserver.info: invalid type: string “2377221647”, expected i64”
2026-06-05T09:44:27Z INFO DNS record created (dns.record-created) hostname = “…”, details = “…”, type = “TXT”, value = [“v=spf1 a -all”]
2026-06-05T09:44:27Z WARN Task failed during processing (task-manager.task-failed) id = …, details = “DnsManagement”, reason = “Failed to set DNS RRSet for …/TXT: Failed to set DNS RRSet: API error: Failed to parse INWX nameserver.info: invalid type: string “2377221647”, expected i64”
Stalwart Version
v0.16.x
Installation Method
Binary (Linux)
Database Backend
RocksDB
Blob Storage
RocksDB
Search Engine
Internal
Directory Backend
Internal
Additional Context
In stalwartlabs/dns-update → src/providers/inwx.rs:
struct NameserverRecord {
id: i64, // INWX now returns string IDs
...
}
INWX announcement (via third-party clients): record IDs from nameserver.info / nameserver.createRecord are now strings; nameserver.deleteRecord, nameserver.updateRecord, and nameserver.info (recordId) must also use string IDs.
References:
- inwx API seems to have changed · Issue #13 · nrdcg/goinwx · GitHub
- lego/CHANGELOG.md at master · go-acme/lego · GitHub (lego v4.29.0:
inwx: fix API breaking changes with record IDs)
Suggested fix
In dns-update/src/providers/inwx.rs:
- Change
NameserverRecord.idtoString(or a newtype / deserializer accepting bothstringandintegerfor backward compatibility with INWX sandbox). - Pass
"id"as a JSON string innameserver.deleteRecord(and any update calls).
Example (minimal):
#[derive(Deserialize, Debug, Clone)]
struct NameserverRecord {
id: String,
// ...
}
// deleteRecord:
self.call("nameserver.deleteRecord", json!({ "id": stale.id }))
Optionally add a unit/integration test with mocked nameserver.info JSON using "id": "2377221647".
Stalwart depends on dns-update = "0.5" (crates/common/Cargo.toml); a patch release dns-update 0.5.1 + Stalwart bump would ship the fix.
Note: ACME itself is Stalwart’s native Rust implementation; only DNS updates go through dns-update (not lego).
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.
on