eclipse-vertx/vert.x · error

412 Precondition Failed

Error message

412 Precondition Failed

What it means

SC_PRECONDITION_FAILED is the HttpResponseExpectation constant for HTTP 412 Precondition Failed. Vert.x supplies it for response validation; a 412 failing this expectation surfaces '412 Precondition Failed'. The server evaluated a request precondition header (If-Match, If-None-Match, If-Unmodified-Since) and it evaluated to false, so the operation was aborted to protect the resource state.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/http/HttpResponseExpectation.java:210

  /**
   * 409 Conflict
   */
  HttpResponseExpectation SC_CONFLICT = status(409);

  /**
   * 410 Gone
   */
  HttpResponseExpectation SC_GONE = status(410);

  /**
   * 411 Length Required
   */
  HttpResponseExpectation SC_LENGTH_REQUIRED = status(411);

  /**
   * 412 Precondition Failed
   */
  HttpResponseExpectation SC_PRECONDITION_FAILED = status(412);

  /**
   * 413 Request Entity Too Large
   */
  HttpResponseExpectation SC_REQUEST_ENTITY_TOO_LARGE = status(413);

  /**
   * 414 Request-URI Too Long
   */
  HttpResponseExpectation SC_REQUEST_URI_TOO_LONG = status(414);

  /**
   * 415 Unsupported Media Type
   */
  HttpResponseExpectation SC_UNSUPPORTED_MEDIA_TYPE = status(415);

  /**
   * 416 Requested Range Not Satisfiable

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Re-fetch the resource to get the current ETag/Last-Modified, then resend the conditional request
  2. Drop the precondition header if your operation does not actually need state protection
  3. Merge/rebase your change on top of the current resource representation before resending
  4. Verify you are not caching and reusing stale ETags across requests
  5. If persistent, investigate concurrent writers and adopt server-side locking or versioned updates

Example fix

// before
request.putHeader("If-Match", cachedEtag).sendJson(body); // 412
// after
webClient.get(path).send()
  .onSuccess(r -> {
    String etag = r.getHeader("ETag");
    webClient.put(path).putHeader("If-Match", etag).sendJson(body);
  });
Defensive patterns

Strategy: retry

Validate before calling

// Fetch a fresh precondition value immediately before the write
String etag = awaitGet(path).getHeader("ETag");
if (etag == null || etag.isBlank()) { dropPreconditionOrRecheck(); }

Type guard

boolean isPreconditionFailed(Throwable t) {
  return t instanceof VertxHttpResponseException
    && ((VertxHttpResponseException) t).getResponse().statusCode() == 412;
}

Try / catch

if (isPreconditionFailed(t)) { refetchEtagAndRetryOnce(); } else { throw t; }

Prevention

When it happens

Trigger: Issuing conditional PUT/DELETE/PATCH via Vert.x WebClient with If-Match/If-None-Match/If-Unmodified-Since headers while the resource has changed since the precondition value was obtained (stale ETag or timestamp).

Common situations: Optimistic concurrency with ETags where another writer updated the resource between your GET and PUT, caching layers reusing old ETags, clock-skewed If-Unmodified-Since values, conditional GET caches (If-None-Match) invalidated server-side.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/27154ca154cc5ab5. Report an issue: GitHub.