fix(api): surface real provider error on apply/check instead of generic internal error

resolve (shared by Check/Apply) and Apply now wrap GetRecords/ApplyChanges
failures in service.ErrProviderUnavailable, matching ZoneRecords' existing
behavior. handleApply/handleCheck use errors.Is against it to return 502
with the real provider message (e.g. Selectel's 409 conflict body) instead
of masking every failure as a generic 500 "internal error"; non-provider
errors (decrypt/db/loader) are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
This commit is contained in:
2026-07-05 15:53:27 +07:00
parent 6f9958af60
commit 879e9e14b1
4 changed files with 190 additions and 6 deletions
+15 -2
View File
@@ -43,7 +43,14 @@ func (a *API) handleCheck(w http.ResponseWriter, r *http.Request) {
log.Printf("api: set domain status (error) failed: %v", serr)
}
log.Printf("api: check failed: %v", err)
writeErr(w, http.StatusInternalServerError, "internal error")
// A provider failure (e.g. Selectel returning a 409 conflict) is safe
// and useful to show the user as-is; any other failure (decrypt/db/loader)
// stays a generic "internal error" to avoid leaking internals.
if errors.Is(err, service.ErrProviderUnavailable) {
writeErr(w, http.StatusBadGateway, service.ProviderMessage(err))
} else {
writeErr(w, http.StatusInternalServerError, "internal error")
}
return
}
// Manual check persists status/history only — no notification. Notify
@@ -79,7 +86,13 @@ func (a *API) handleApply(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
log.Printf("api: apply failed: %v", err)
writeErr(w, http.StatusInternalServerError, "internal error")
// Same distinction as handleCheck: surface the real provider message,
// keep everything else generic.
if errors.Is(err, service.ErrProviderUnavailable) {
writeErr(w, http.StatusBadGateway, service.ProviderMessage(err))
} else {
writeErr(w, http.StatusInternalServerError, "internal error")
}
return
}
writeJSON(w, http.StatusOK, toChangesetResponse(cs))