Safe and idempotent HTTP methods: why retrying POST is risky and PUT isn't

What RFC 9110 means by safe and idempotent methods, which ones a client may resend after a dropped connection, why POST and PATCH need care, and how If-Match makes an update conditional.

DevelopmentWebNetworking

If a connection drops before the response arrives, the client can’t tell whether the server applied the request. Whether it’s fine to send the same request again depends on the method. RFC 9110, the HTTP semantics specification, describes methods by two properties: safe and idempotent.

Safe: the client only asks to read

A safe method is one whose defined semantics are essentially read-only: the client neither requests nor expects any change of state on the server (section 9.2.1). Of the methods RFC 9110 defines, GET, HEAD, OPTIONS and TRACE are safe.

Safe doesn’t mean free of side effects. The spec still counts a server that logs every request, or an ad click that charges an advertising account, as safe. What matters is that the client didn’t ask for that behaviour. The reverse also holds: if a resource deletes something on page?do=delete via GET, its owner MUST disable that action for safe methods, because link checkers, prefetchers and search crawlers send GET to every URI they find.

Idempotent: same intended effect however many times you send it

A method is idempotent if the intended effect on the server of several identical requests is the same as the effect of one (section 9.2.2). PUT, DELETE and the safe methods qualify. PUT asks the server to set the target’s state to the enclosed representation, so sending the same body twice leaves the same state. POST asks the resource to process the content by its own rules, so sending it twice can create two orders.

It doesn’t promise the same response. The spec says repeating a request has the same intended effect even if the first one succeeded, “though the response might differ”. A repeated DELETE might get a 404 the second time, for example, but the resource is gone either way. Servers may also log each request or keep a revision history.

Method Safe Idempotent
GET, HEAD, OPTIONS, TRACE yes yes
PUT, DELETE no yes
POST, PATCH no no

The retry rules

Automatic retries are where the distinction matters. A client may resend an idempotent request on a new connection if the old one closed before it read the response. For a non-idempotent request, a client SHOULD NOT retry automatically unless it has some way to know the request is in fact idempotent, or to detect that the original was never applied. A proxy MUST NOT automatically retry non-idempotent requests, and a client SHOULD NOT automatically retry a failed automatic retry. The spec also notes that some clients take the riskier route of resending a POST when an idle persistent connection closes.

PATCH and If-Match

RFC 5789, which defines PATCH, states that it is neither safe nor idempotent, but that a PATCH can be sent in an idempotent way. When the patch format assumes a known starting state, the client SHOULD make the request conditional, for example by putting the last strong ETag it received in If-Match so that the request fails if the resource has changed since. When an If-Match condition is false, the server MUST NOT perform the method. It may answer 412 Precondition Failed, or 2xx if the same change looks already applied (RFC 9110 section 13.1.1). ETags themselves come up in no-cache vs no-store.

When a POST has to be retried

The spec allows a client to repeat a POST automatically if it knows, through design or configuration, that the request semantics are actually idempotent. One API design accepts a unique key with each request, uses it to recognize retries of the same request, and returns the result of an operation that has already completed. The IETF has a draft Idempotency-Key header for this, but as of 8 October 2026 it isn’t an RFC and the draft has expired. The 303 response that sends a browser from a form POST to a result page is covered in 301, 302, 307 or 308?.

A safe request with a body: QUERY

RFC 10008, published in June 2026, defines the QUERY method. It carries a request body like POST, but it is safe and idempotent, so it can be resent after a dropped connection. A cross-origin QUERY request from a browser requires a CORS preflight because QUERY is not a CORS-safelisted method. Since the spec is new, check that your client, server and any proxies actually support it.

Sources

Links and content checked on 8 October 2026.

Back to the blog