apache/druid · error · IllegalStateException

Failed to serialize TableDefn

Error message

Failed to serialize TableDefn

What it means

Thrown by CatalogUtils.toString(Object) when the pretty-printer fails to serialize the given object (usually a TableDefn) to JSON, i.e. JsonProcessingException. Since definition objects are expected to be plain JSON-friendly POJOs, a failure here indicates the object contains non-serializable content (self-references, invalid types) or a Jackson configuration problem.

Source

Thrown at server/src/main/java/org/apache/druid/catalog/model/CatalogUtils.java:185

    return String.join("\n", lines) + "\n";
  }

  /**
   * Catalog-specific quick & easy implementation of {@code toString()} for objects
   * which are primarily representations of JSON objects. Use only for cases where the
   * {@code toString()} is for debugging. Also, assumes that the
   * type can serialized using the default mapper: this trick doesn't work for types that
   * require custom Jackson extensions. The catalog, however, has a simple type
   * hierarchy, which is not extended via extensions, and so the default object mapper is
   * fine.
   */
  public static String toString(Object obj)
  {
    try {
      return DefaultObjectMapper.INSTANCE.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
    }
    catch (JsonProcessingException e) {
      throw new ISE("Failed to serialize TableDefn");
    }
  }

  public static <T> List<T> concatLists(
      @Nullable final List<T> base,
      @Nullable final List<T> additions
  )
  {
    return Stream
        .of(base, additions)
        .filter(Objects::nonNull)
        .flatMap(Collection::stream)
        .collect(Collectors.toList());
  }

  /**
   * Get a string parameter that can either be null or non-blank.
   */

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Check the offending object's fields for types Jackson cannot serialize; annotate or remove them (@JsonIgnore, serializable types)
  2. Inspect the swallowed JsonProcessingException by reproducing with DefaultObjectMapper.INSTANCE.writeValueAsString in a debugger/log (note the ISE drops the cause)
  3. Ensure custom definition subclasses keep fields JSON-friendly and registered with the object mapper

Example fix

// before
class MyDefn extends TableDefn {
  private transient java.io.InputStream data; // non-serializable field
}
// after
class MyDefn extends TableDefn {
  @JsonIgnore
  private transient java.io.InputStream data;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check serializability before relying on toString
try {
  String s = DefaultObjectMapper.INSTANCE.writeValueAsString(obj);
} catch (JsonProcessingException e) {
  log.error("Object {} is not JSON-serializable", obj.getClass(), e);
}

Try / catch

try {
  String s = CatalogUtils.toString(defn);
} catch (IllegalStateException e) {
  if ("Failed to serialize TableDefn".equals(e.getMessage())) {
    log.error("TableDefn {} has non-serializable fields", defn.getId());
  }
}

Prevention

When it happens

Trigger: Calling toString() on a TableDefn (or passing a definition object to CatalogUtils.toString) whose fields cannot be mapped to JSON: e.g. a field holding an object with no properties, an unserializable type added via subclassing, or a corrupted object graph built outside normal deserialization paths.

Common situations: Custom TableDefn subclasses adding non-POJO fields, objects deserialized into unexpected shapes (raw Maps containing non-JSON values), debugging/logging code calling toString on partially constructed definitions.

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/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/5f6a59e868308358. Report an issue: GitHub.