cocoindex-io/cocoindex · error · ValueError

Iggy does not support Kafka-style tombstones. Provide deleti

Error message

Iggy does not support Kafka-style tombstones. Provide deletion_value_fn or encode deletes in the payload.

What it means

Unlike Kafka, Iggy has no native tombstone records for deletes. When a reconciliation sees a desired state of non-existence and the connector has no deletion_value_fn configured, it raises ValueError rather than emitting an ambiguous delete.

Source

Thrown at python/cocoindex/connectors/iggy/_target.py:128

            partitioning=self._partition,
            messages=messages,
        )

    def reconcile(
        self,
        key: coco.StableKey,
        desired_target_state: bytes | str | coco.NonExistenceType,
        prev_possible_records: Collection[_MessageFingerprint],
        prev_may_be_missing: bool,
        /,
    ) -> coco.TargetReconcileOutput[_MessageAction, _MessageFingerprint] | None:
        assert isinstance(key, (bytes, str))

        if coco.is_non_existence(desired_target_state):
            if not prev_possible_records and not prev_may_be_missing:
                return None
            if self._deletion_value_fn is None:
                raise ValueError(
                    "Iggy does not support Kafka-style tombstones. "
                    "Provide deletion_value_fn or encode deletes in the payload."
                )
            deletion_value = self._deletion_value_fn(key)
            return coco.TargetReconcileOutput(
                action=_MessageAction(key=key, value=deletion_value),
                sink=self._sink,
                tracking_record=coco.NON_EXISTENCE,
            )

        # Upsert case
        if isinstance(desired_target_state, bytes):
            target_fp = fingerprint_bytes(desired_target_state)
        else:
            target_fp = fingerprint_str(desired_target_state)

        if not prev_may_be_missing and all(
            prev == target_fp for prev in prev_possible_records

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Provide deletion_value_fn when constructing the Iggy target so deletes can be encoded as a message value
  2. Encode deletes inside the normal payload (e.g. a flag in the message value) and handle them downstream
  3. If deletes are impossible/unnecessary, ensure prev records and prev_may_be_missing are handled so no delete action is generated

Example fix

// before
target = iggy.TableTarget(client, stream="s", topic="t", ...)
// after
target = iggy.TableTarget(client, stream="s", topic="t", deletion_value_fn=lambda key: encode_tombstone(key), ...)
Defensive patterns

Strategy: validation

Validate before calling

if deletion_value_fn is None:
    raise ValueError("Iggy target requires deletion_value_fn to handle deletes")

Try / catch

try:
    await app.update()
except ValueError as e:
    if "tombstones" in str(e):
        reconfigure_target_with_deletion_value_fn()

Prevention

When it happens

Trigger: Reconcile output for a key with coco.is_non_existence(desired_target_state) (a delete) on an Iggy target constructed without deletion_value_fn — e.g. during update when a source record disappears.

Common situations: Source rows/files deleted between runs causing target deletes; switching a target from Kafka (tombstones supported) to Iggy without adapting delete handling.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08). Data as JSON: /api/errors/c52aa82023b0435c. Report an issue: GitHub.