pathwaycom/pathway · error · ValueError
Trying to delete a row in {type(self)} but deletions_enabled
Error message
Trying to delete a row in {type(self)} but deletions_enabled is set to False. What it means
Raised by Pathway's Python input connector when a custom ConnectorSubject calls subject.remove(key, ...) while the connector was created with deletions_enabled=False. Deletions are opt-in for python connectors, so emitting a retract on an append-only connector is rejected at the source rather than dropped silently, which would desynchronize downstream state from reality.
Source
Thrown at python/pathway/io/python/__init__.py:286
if self._session_type == SessionType.NATIVE:
self._buffer.put((PythonConnectorEventType.INSERT, key, values))
elif self._session_type == SessionType.UPSERT:
if not self._deletions_enabled:
raise ValueError(
f"Trying to modify a row in {type(self)} but deletions_enabled is set to False."
)
self._buffer.put((PythonConnectorEventType.INSERT, key, values))
else:
raise NotImplementedError(f"session type {self._session_type} not handled")
def _remove(
self, key: Pointer, message: bytes, metadata: bytes | None = None
) -> None:
self._remove_inner(key, self._get_values_dict(message, metadata))
def _remove_inner(self, key: Pointer | None, values: dict[str, Any]) -> None:
if not self._deletions_enabled:
raise ValueError(
f"Trying to delete a row in {type(self)} but deletions_enabled is set to False."
)
self._buffer.put((PythonConnectorEventType.DELETE, key, values))
def _read(self) -> Any:
"""Allows to retrieve data from a buffer.
Should not be called directly.
"""
return self._buffer.get()
def _is_internal(self) -> bool:
"""
The Python connector is internal in case it is used to implement an internal
The Pathway Live Data Framework feature rather than to read the data from an external source.
We need this distinction, because internal usages don't read user data and
aren't a part of the external perimeter, which is currently persisted. ThereforeView on GitHub (pinned to fa2f74a464)
Solutions
- Pass deletions_enabled=True to pw.io.python.read so remove() is honored.
- If deletions must stay disabled, filter tombstones inside the subject's run() and never call remove().
- For batch/static sources that finish and never retract, keep deletions_enabled=False and simply omit any delete emissions.
Example fix
# before
def run(self):
for key, payload, deleted in feed:
if deleted:
self.remove(key, payload) # not allowed: deletions disabled
pw.io.python.read(Subj(), schema=S, deletions_enabled=False)
# after
pw.io.python.read(Subj(), schema=S) # deletions_enabled=True Defensive patterns
Strategy: validation
Validate before calling
source_can_delete = True pw.io.python.read(Subj(), schema=S, deletions_enabled=source_can_delete)
Prevention
- Pass deletions_enabled=True for changelog/tombstone-carrying feeds.
- Filter tombstones inside subject.run() if deletions must stay disabled.
- Re-check the flag whenever a source gains delete events.
When it happens
Trigger: A ConnectorSubject.run() that calls self.remove(key, payload) for tombstoned events, while pw.io.python.read(subject, ..., deletions_enabled=False) was configured (e.g. to reduce memory usage in static workloads).
Common situations: Reading a changelog/DEBEZIUM-style feed where deletes appear, with deletions_enabled=False chosen for performance; upgrading an append-only prototype to a real source that now sends tombstones without flipping the flag back.
Related errors
- Trying to modify a row in {type(self)} but deletions_enabled
- You can't use the same ConnectorSubject object in more than
- Invalid schema. Time columns must be int or float.
- demo.replay_csv_with_time: unit should be either 's', 'ms, '
- Join received extra kwargs. You probably want to use TableLi
AI-assisted analysis of pathwaycom/pathway@fa2f74a464 (2026-08-15).
Data as JSON: /api/errors/5b9e652f1e388cc2.
Report an issue: GitHub.