{"record":{"id":"940fbcb24025056d","repo":"eclipse-vertx/vert.x","slug":"428-precondition-required-rfc6585","errorCode":null,"errorMessage":"428 Precondition Required (RFC6585)","messagePattern":"428 Precondition Required \\(RFC6585\\)","errorType":"http","errorClass":null,"httpStatus":428,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/http/HttpResponseExpectation.java","lineNumber":270,"sourceCode":"  /**\n   * 424 Failed Dependency (WebDAV, RFC4918)\n   */\n  HttpResponseExpectation SC_FAILED_DEPENDENCY = status(424);\n\n  /**\n   * 425 Unordered Collection (WebDAV, RFC3648)\n   */\n  HttpResponseExpectation SC_UNORDERED_COLLECTION = status(425);\n\n  /**\n   * 426 Upgrade Required (RFC2817)\n   */\n  HttpResponseExpectation SC_UPGRADE_REQUIRED = status(426);\n\n  /**\n   * 428 Precondition Required (RFC6585)\n   */\n  HttpResponseExpectation SC_PRECONDITION_REQUIRED = status(428);\n\n  /**\n   * 429 Too Many Requests (RFC6585)\n   */\n  HttpResponseExpectation SC_TOO_MANY_REQUESTS = status(429);\n\n  /**\n   * 431 Request Header Fields Too Large (RFC6585)\n   */\n  HttpResponseExpectation SC_REQUEST_HEADER_FIELDS_TOO_LARGE = status(431);\n\n  /**\n   * Any 5XX server error\n   */\n  HttpResponseExpectation SC_SERVER_ERRORS = status(500, 600);\n\n  /**\n   * 500 Internal Server Error","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/http/HttpResponseExpectation.java#L252-L288","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nrequest.putHeader(\"If-Match\", etag); // absent before\nclient.put(8080, \"localhost\", \"/items/1\").send(body);\n// after\nString etag = getResponse.headers().get(\"ETag\");\nclient.put(8080, \"localhost\", \"/items/1\")\n  .putHeader(\"If-Match\", etag)\n  .send(body);","handlingStrategy":"validation","validationCode":"Objects.requireNonNull(etag, \"ETag required for conditional update on /items\");","typeGuard":"boolean is428(HttpClientResponse resp) { return resp.statusCode() == 428; }","tryCatchPattern":"put().onFailure(err -> {\n  if (isCauseStatus(err, 428)) refetchEtagAndRetryWithIfMatch();\n});","preventionTips":["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"],"tags":["http","concurrency","conditional-request","vertx-http-client"],"backgroundTag":"http-error-status","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}