Files
John Detter 280818631d client-api: stop logging suspended-database errors as 500s (#4918)
# Description of Changes

Disclaimer: This description was written by claude:

The two `.leader()` call sites in
[`client-api/src/routes/database.rs`](crates/client-api/src/routes/database.rs)
and
[`client-api/src/routes/subscribe.rs`](crates/client-api/src/routes/subscribe.rs)
pipe `GetLeaderHostError` through `log_and_500`, which:

1. Logs every error variant at `error` level — including `Suspended`,
`Bootstrapping`, `NoLeader`, etc., which are normal operational states.
This produces noisy log lines like:
   ```
ERROR /app/.../client-api/src/lib.rs:623: internal error: database is
suspended
   ```
2. Forces every such error into a **500 Internal Server Error**
response, even when the appropriate status code is something else (e.g.
503 Service Unavailable for a suspended database).

`GetLeaderHostError` already implements
`Into<axum::response::ErrorResponse>` with the correct per-variant
mapping:

| Variant | Status |
|---|---|
| `NoSuchDatabase` | 404 Not Found |
| `LaunchError`, `Misdirected` | 500 Internal Server Error |
| `NoNodeId`, `NoLeader`, `ControlConnection`, `Suspended`,
`Bootstrapping` | 503 Service Unavailable |

The standalone implementation already uses `?`-propagation directly.
This PR makes the two client-api call sites match that pattern.

## Result

- Suspended / bootstrapping / no-leader databases now return **503**
instead of 500.
- These expected states no longer produce `error`-level log spam in the
request path. Genuinely unexpected internal errors elsewhere in the
codebase continue to log via `log_and_500` unchanged.

# API and ABI breaking changes

None

# Expected complexity level and risk

1

# Testing

- [ ] Deploy to staging to see if we still see this error when trying to
access a suspended database
2026-04-30 16:24:02 +00:00
..
2025-08-12 18:20:58 +00:00

⚠️ Internal Crate ⚠️

This crate is intended for internal use only. It is not stable and may change without notice.