apache/seatunnel · error · SeaTunnelRuntimeException

COMMON-02

COMMON-02

Error message

<identifier> JSON convert/parse '<payload>' operation failed.

What it means

TypesenseRowSerializer.serializeRow converts a SeaTunnelRow into a JSON document string for Typesense indexing using Jackson's ObjectMapper. When writeValueAsString throws a JsonProcessingException (e.g. an unserializable value, non-numeric NaN, or a type Jackson cannot represent), the connector rethrows it as CommonError.jsonOperationError with the offending document payload. This indicates the row's fields cannot be converted to a valid Typesense JSON document.

Source

Thrown at seatunnel-connectors-v2/connector-typesense/src/main/java/org/apache/seatunnel/connectors/seatunnel/typesense/serialize/sink/TypesenseRowSerializer.java:65

        this.keyExtractor =
                KeyExtractor.createKeyExtractor(
                        seaTunnelRowType,
                        collectionInfo.getPrimaryKeys(),
                        collectionInfo.getKeyDelimiter());
    }

    @Override
    public String serializeRow(SeaTunnelRow row) {
        String key = keyExtractor.apply(row);
        Map<String, Object> document = toDocumentMap(row, seaTunnelRowType);
        if (StringUtils.isNotBlank(key)) {
            document.put("id", key);
        }
        String documentStr;
        try {
            documentStr = objectMapper.writeValueAsString(document);
        } catch (JsonProcessingException e) {
            throw CommonError.jsonOperationError("Typesense", "document:" + document.toString(), e);
        }
        return documentStr;
    }

    @Override
    public String serializeRowForDelete(SeaTunnelRow row) {
        String key = keyExtractor.apply(row);
        Map<String, Object> document = toDocumentMap(row, seaTunnelRowType);
        String id = document.get("id").toString();
        if (StringUtils.isNotBlank(key)) {
            id = key;
        }
        return id;
    }

    private Map<String, Object> toDocumentMap(SeaTunnelRow row, SeaTunnelRowType rowType) {
        String[] fieldNames = rowType.getFieldNames();
        Map<String, Object> doc = new HashMap<>(fieldNames.length);

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Inspect the payload shown in the error message ('document:...') to find the field holding the non-serializable value and fix the upstream data or transform (e.g. replace NaN/Infinity with null).
  2. Ensure the SeaTunnel catalog type of every column is JSON-serializable (basic types, arrays, maps, rows); cast or transform unsupported column types before the Typesense sink.
  3. If the ObjectMapper needs feature flags (e.g. serialize NaN as strings), configure serialization features on the serializer's objectMapper before running the job.
  4. Enable debug logging and run the job in local mode to capture the full JsonProcessingException cause chained in this error.

Example fix

// before: row contains NaN double from source
row.setField(2, Double.NaN); // Typesense sink -> jsonOperationError
// after: sanitize before sink
row.setField(2, Double.isNaN(value) || Double.isInfinite(value) ? null : value);
Defensive patterns

Strategy: try-catch

Validate before calling

// before calling serializeRow, sanity-check serializable fields
for (int i = 0; i < row.getArity(); i++) {
  Object v = row.getField(i);
  if (v instanceof Double d && (d.isNaN() || d.isInfinite())) {
    throw new IllegalArgumentException("field " + i + " not JSON-serializable: " + v);
  }
}

Type guard

static boolean isJsonSerializable(Object v) {
  return v == null || v instanceof String || v instanceof Number
      || v instanceof Boolean || v instanceof Map || v instanceof Iterable || v.getClass().isArray();
}

Try / catch

try {
  String doc = serializer.serializeRow(row);
} catch (org.apache.seatunnel.api.common.SeaTunnelRuntimeException e) {
  if (e.getSeaTunnelErrorCode() == CommonError.code) {
    LOG.error("Typesense serialize failed for payload: {}", e.getFormattedMessage(), e);
    // skip, dead-letter, or fix row before retry
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling serializeRow on a SeaTunnelRow whose map/document contains values Jackson cannot serialize (e.g. Infinity/NaN doubles with default ObjectMapper settings, raw Java objects with no bean properties, or cyclic structures). Any SeaTunnelRow -> Typesense document conversion failure inside writeValueAsString triggers this.

Common situations: Source data contains NaN or Infinity floating point values loaded from databases or files; a custom SeaTunnelRow field type (e.g. a POJO or byte[]) is passed through without being mapped to a JSON-compatible SeaTunnelType; schema fields changed upstream so document values no longer match expected types.

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/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/f894d40ba924813f. Report an issue: GitHub.