pathwaycom/pathway · error · ValueError
Trying to modify a row in {type(self)} but deletions_enabled
Error message
Trying to modify 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 emits a modification (an upsert of an existing key) through a session of SessionType.UPSERT while deletions_enabled=False was passed to pw.io.python.read. With deletions disabled the engine assumes an append-only stream, so an upsert-style rewrite of a key is a contract violation and is rejected instead of silently dropping or corrupting state.
Source
Thrown at python/pathway/io/python/__init__.py:272
) -> dict[str, Any]:
match self._pw_format:
case "json":
values = json.loads(message.decode(encoding="utf-8"))
case "raw":
values = {"data": message.decode(encoding="utf-8")}
case _:
assert self._pw_format == "binary"
values = {"data": message}
if metadata is not None:
values["_metadata"] = json.loads(metadata.decode(encoding="utf-8"))
return values
def _add_inner(self, key: Pointer | None, values: dict[str, Any]) -> None:
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))
View on GitHub (pinned to fa2f74a464)
Solutions
- Set deletions_enabled=True (default) in pw.io.python.read so updates to an existing key are legal.
- Or make the subject truly append-only: never reuse a key in next(); derive unique keys per event (e.g. include a sequence number or timestamp).
- If only late corrections arrive, emit the correction as a new row with a new key and dedupe downstream with reducers instead of mutating the key.
Example fix
# before
def run(self):
self.next("row-1", {"v": 1})
self.next("row-1", {"v": 2}) # modification of existing key
pw.io.python.read(Subj(), schema=S, deletions_enabled=False)
# after
pw.io.python.read(Subj(), schema=S) # deletions_enabled=True allows upserts Defensive patterns
Strategy: validation
Validate before calling
may_update_keys = True # set to False only for truly append-only sources pw.io.python.read(Subj(), schema=S, deletions_enabled=may_update_keys)
Prevention
- Set deletions_enabled=True whenever the source can emit the same key twice.
- Derive unique keys per event if you intend an append-only connector.
- Document the subject's key policy in its docstring so callers pick the right flag.
When it happens
Trigger: Implementing a ConnectorSubject whose run() calls subject.next(key, values) twice with the same key (the second call is a modify) while the connector was created with pw.io.python.read(subject, ..., deletions_enabled=False); or commit/replay logic that re-emits rows.
Common situations: Feeding an upsert source (e.g. a dict-backed feed or Kafka compacted topic) into a pipeline configured for append-only processing to save memory; porting an existing subject from UPSERT semantics to static mode and forgetting duplicate keys can occur.
Related errors
- Trying to delete 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/5895d61068599b59.
Report an issue: GitHub.