eclipse-vertx/vert.x · error
428 Precondition Required (RFC6585)
Error message
428 Precondition Required (RFC6585)
What it means
SC_PRECONDITION_REQUIRED is an HttpResponseExpectation constant for HTTP 428 (RFC6585). The server requires the request to be conditional — carrying a header such as If-Match or If-Unmodified-Since — to prevent lost-update races. Vert.x exposes it so clients can assert or handle this requirement.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/http/HttpResponseExpectation.java:270
/** * 424 Failed Dependency (WebDAV, RFC4918) */ HttpResponseExpectation SC_FAILED_DEPENDENCY = status(424); /** * 425 Unordered Collection (WebDAV, RFC3648) */ HttpResponseExpectation SC_UNORDERED_COLLECTION = status(425); /** * 426 Upgrade Required (RFC2817) */ HttpResponseExpectation SC_UPGRADE_REQUIRED = status(426); /** * 428 Precondition Required (RFC6585) */ HttpResponseExpectation SC_PRECONDITION_REQUIRED = status(428); /** * 429 Too Many Requests (RFC6585) */ HttpResponseExpectation SC_TOO_MANY_REQUESTS = status(429); /** * 431 Request Header Fields Too Large (RFC6585) */ HttpResponseExpectation SC_REQUEST_HEADER_FIELDS_TOO_LARGE = status(431); /** * Any 5XX server error */ HttpResponseExpectation SC_SERVER_ERRORS = status(500, 600); /** * 500 Internal Server Error
View on GitHub (pinned to fb308bd8c3)
Solutions
- Fetch the resource's ETag (or Last-Modified) and resend with an If-Match (or If-Unmodified-Since) header.
- Handle a resulting 412 by re-reading the resource, merging changes, and retrying with the fresh ETag.
- Adopt conditional updates in the client as standard practice for mutable resources.
- Check for server upgrades that newly mandate conditional requests.
Example fix
// before
request.putHeader("If-Match", etag); // absent before
client.put(8080, "localhost", "/items/1").send(body);
// after
String etag = getResponse.headers().get("ETag");
client.put(8080, "localhost", "/items/1")
.putHeader("If-Match", etag)
.send(body); Defensive patterns
Strategy: validation
Validate before calling
Objects.requireNonNull(etag, "ETag required for conditional update on /items");
Type guard
boolean is428(HttpClientResponse resp) { return resp.statusCode() == 428; } Try / catch
put().onFailure(err -> {
if (isCauseStatus(err, 428)) refetchEtagAndRetryWithIfMatch();
}); Prevention
- Always fetch and send If-Match/If-Unmodified-Since on mutable resources
- Handle 412 conflicts by re-reading and merging
- Store ETags alongside cached resources
- Watch for server upgrades that introduce mandatory conditional headers
When it happens
Trigger: Performing PUT/DELETE/PATCH without conditional headers against an optimistic-concurrency API that mandates If-Match/If-Unmodified-Since. Observed when an expectation chain expects success but the server replies 428.
Common situations: APIs enforcing optimistic locking introduced in a newer server version; clients that never set ETag-based conditional headers; concurrent editors overwriting each other before the policy was enforced.
Related errors
- 412 Precondition Failed
- 421 Misdirected Request
- 422 Unprocessable Entity (WebDAV, RFC4918)
- 423 Locked (WebDAV, RFC4918)
- 424 Failed Dependency (WebDAV, RFC4918)
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/940fbcb24025056d.
Report an issue: GitHub.