apache/iceberg · error · RESTException

Failed to encode request body: %s

Error message

Failed to encode request body: %s

What it means

HTTPRequest.encodedBody serializes the request body: Maps go through RESTUtil.encodeFormData, other non-null objects through the shared Jackson ObjectMapper. If Jackson throws JsonProcessingException, the client wraps it in a RESTException with this message. It means the request payload could not be serialized to JSON before sending.

Source

Thrown at core/src/main/java/org/apache/iceberg/rest/HTTPRequest.java:109

  /** Returns the raw, unencoded request body. */
  @Nullable
  @Value.Redacted
  Object body();

  /** Returns the encoded request body as a string. */
  @Value.Lazy
  @Nullable
  @Value.Redacted
  default String encodedBody() {
    Object body = body();
    if (body instanceof Map) {
      return RESTUtil.encodeFormData((Map<?, ?>) body);
    } else if (body != null) {
      try {
        return mapper().writeValueAsString(body);
      } catch (JsonProcessingException e) {
        throw new RESTException(e, "Failed to encode request body: %s", body);
      }
    }
    return null;
  }

  /**
   * Returns the {@link ObjectMapper} to use for encoding the request body. The default is {@link
   * RESTObjectMapper#mapper()}.
   */
  @Value.Default
  default ObjectMapper mapper() {
    return RESTObjectMapper.mapper();
  }

  @Value.Check
  default void check() {
    if (path().startsWith("/")) {
      throw new RESTException(

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Send Iceberg's REST request types (e.g. RegisterTableRequest, UpdateNamespacePropertiesRequest) instead of ad-hoc objects.
  2. Inspect the chained JsonProcessingException cause to find the offending property and fix or exclude it (@JsonIgnore-style exclusion in your own mapper-compatible type).
  3. Ensure body getters never throw and the object has no cyclic references.
  4. If sending a form, pass a Map so it is encoded as form data instead of JSON.

Example fix

// before
request.withBody(myDomainObjectWithCycles);
// after
request.withBody(RegisterTableRequest.builder()
    .name(tableName)
    .location(location)
    .build());
Defensive patterns

Strategy: type-guard

Type guard

static boolean jsonSerializable(Object body) {
  try {
    RESTObjectMapper.mapper().writeValueAsString(body);
    return true;
  } catch (JsonProcessingException e) {
    return false;
  }
}

Try / catch

try {
  request.withBody(body);
} catch (RESTException e) {
  if (e.getMessage().startsWith("Failed to encode request body")) {
    // inspect e.getCause() for the offending property; use a REST request type
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling HTTPRequest.post(...).withBody(obj) where obj is not JSON-serializable — e.g. an object with self-references (infinite recursion), a type Jackson has no serializer for, or a POJO with failing getters that throw during serialization.

Common situations: Passing raw domain objects instead of Iceberg REST request types (like RegisterTableRequest); non-serializable custom types (InputStream, lambdas) in the body; getters that throw IllegalStateException during property access.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/1bb8690d3896aef8. Report an issue: GitHub.