From ded23b711f03b9a20ef026a7eb7ad40c8e491171 Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 7 Sep 2026 20:15:27 +0200 Subject: [PATCH] swarm-controller: 409 instead of 400 for a terminal-state rejection --- swarm-controller/src/main.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/swarm-controller/src/main.rs b/swarm-controller/src/main.rs index 6ebe3032..962a8dac 100644 --- a/swarm-controller/src/main.rs +++ b/swarm-controller/src/main.rs @@ -794,7 +794,8 @@ fn declaration_target( request_body = SetAgentStateRequest, responses( (status = 200, description = "the declaration as now published", body = Vec), - (status = 400, description = "a name is not an identifier, the hive is not in this swarm, the state is unknown, or the agent is already declared destroyed (terminal — problem+json)", body = String), + (status = 400, description = "a name is not an identifier, the hive is not in this swarm, or the state is unknown (problem+json)", body = String), + (status = 409, description = "the agent is already declared destroyed, a terminal state the request tries to move it off of (problem+json)", body = String), (status = 503, description = "no swarm queue is wired up (problem+json)", body = String), (status = 500, description = "the declaration could not be published (problem+json)", body = String), ), @@ -812,11 +813,13 @@ async fn set_agent_state( .into_string(); let declaration = writer.set(&hive, &agent, req.state).await.map_err(|e| { - // A `TerminalStateError` is the caller's mistake (asking to move an - // agent off a state its own doc comment says is terminal), not a - // server fault — everything else here is the pre-existing catch-all. + // A `TerminalStateError` is the caller's mistake, but not a malformed + // request — the request is well-formed, it just conflicts with the + // target resource's current (terminal) state, which per RFC 9110 is + // what 409 exists for, not 400. Everything else here is the + // pre-existing catch-all. if let Some(terminal) = e.downcast_ref::() { - return error_problem(axum::http::StatusCode::BAD_REQUEST, &terminal.to_string()); + return error_problem(axum::http::StatusCode::CONFLICT, &terminal.to_string()); } tracing::warn!(hive = %hive, agent = %agent, error = %format!("{e:#}"), "declaring agent state failed"); error_problem(