pytest-dev/pytest · warning · ValueError
cannot delete key in keywords dict
Error message
cannot delete key in keywords dict
What it means
A ValueError raised by NodeKeywords.__delitem__ whenever code attempts `del node.keywords[key]`. The keywords mapping is a read-only union of a node's own markers and its parent's keywords; pytest deliberately makes deletion impossible to keep the keyword set consistent with the collected node tree. Any del operation, regardless of key, hits this guard.
Solutions
- Do not delete keywords; instead, deselect the item via pytest_collection_modifyitems (config.hook.pytest_deselected).
- If filtering by keyword, build a new list of selected items rather than mutating keywords.
- Use a custom marker on the test rather than relying on dynamically removing keywords.
Example fix
# before
del item.keywords['smoke']
# after
def pytest_collection_modifyitems(items, config):
remaining = [i for i in items if 'smoke' not in i.keywords]
config.hook.pytest_deselected(items=[i for i in items if i not in remaining])
items[:] = remaining Defensive patterns
Strategy: validation
Validate before calling
def remove_keyword(items, key):
return [i for i in items if key not in i.keywords]
# never call del item.keywords[key] Prevention
- Treat node.keywords as read-only.
- Filter items via pytest_collection_modifyitems instead of mutating keywords.
- Document this constraint for plugin authors.
When it happens
Trigger: Calling `del item.keywords['smoke']`, `item.keywords.pop('x')` (if it routes through __delitem__), or any third-party code that mutates the keywords mapping. The method unconditionally raises.
Common situations: Plugins or conftest hooks that try to remove a keyword to influence selection; tests asserting on keywords and trying to clean up; porting code from a dict-like API.
Related errors
- Can't find module at location
- Could not resolve for
- directory argument cannot contain :: selection parts
- file or directory not found
- found no collectors for
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/42adf7853bcf6af7.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/mark/structures.py:682
# Note: we could've avoided explicitly implementing some of the methods
# below and use the collections.abc fallback, but that would be slow.
def __contains__(self, key: object) -> bool:
return key in self._markers or (
self.parent is not None and key in self.parent.keywords
)
def update( # type: ignore[override]
self,
other: Mapping[str, Any] | Iterable[tuple[str, Any]] = (),
**kwds: Any,
) -> None:
self._markers.update(other)
self._markers.update(kwds)
def __delitem__(self, key: str) -> None:
raise ValueError("cannot delete key in keywords dict")
def __iter__(self) -> Iterator[str]:
# Doesn't need to be fast.
yield from self._markers
if self.parent is not None:
for keyword in self.parent.keywords:
# self._marks and self.parent.keywords can have duplicates.
if keyword not in self._markers:
yield keyword
def __len__(self) -> int:
# Doesn't need to be fast.
return sum(1 for keyword in self)
def __repr__(self) -> str:
return f"<NodeKeywords for node {self.node}>"
View on GitHub (pinned to 0d6fbdeffa)