kovidgoyal/kitty · error · RuntimeError
Cannot access the mmap of a closed shared memory object
Error message
Cannot access the mmap of a closed shared memory object
What it means
The `mmap` property was accessed after the SharedMemory object was closed. Close() unmaps the memory and sets the internal _mmap to None, so any later access to .mmap raises RuntimeError instead of returning a dangling pointer. This is a use-after-close guard.
Source
Thrown at kitty/shm.py:157
def __exit__(self, *a: object) -> None:
self.close()
if self.unlink_on_exit:
self.unlink()
@property
def size(self) -> int:
return self._size
@property
def name(self) -> str:
return self._name
@property
def mmap(self) -> mmap.mmap:
ans = self._mmap
if ans is None:
raise RuntimeError('Cannot access the mmap of a closed shared memory object')
return ans
def fileno(self) -> int:
return self._fd
def __repr__(self) -> str:
return f'{self.__class__.__name__}({self.name!r}, size={self.size})'
def close(self) -> None:
"""Closes access to the shared memory from this instance but does
not destroy the shared memory block."""
if self._mmap is not None:
try:
self._mmap.close()
except BufferError:
if not self.ignore_close_failure:
raise
self._mmap = NoneView on GitHub (pinned to 6d5d0c4406)
Solutions
- Keep the SharedMemory object alive as long as any mmap/NumPy view derived from it is used; close only at the very end
- Audit cleanup paths (finally blocks, context managers) for premature close()
- Cache the mmap object before closing is possible only if you also keep the fd/mapping alive — instead, restructure so close happens last
- If another thread closes it, coordinate with a lock or lifetime owner
Example fix
// before buf = shm.mmap shm.close() use(buf) # buf is fine, but any later shm.mmap access is not x = shm.mmap # RuntimeError // after buf = shm.mmap use(buf) shm.close() # close last, after all uses
Defensive patterns
Strategy: type-guard
Validate before calling
if shm._mmap is None:
raise RuntimeError('already closed') # or skip work
# safer: track closed state yourself
closed = False
# ... set closed = True in your own close wrapper Type guard
def is_open(shm) -> bool:
import types
return getattr(shm, '_mmap', None) is not None Try / catch
try:
mm = shm.mmap
except RuntimeError:
shm = SharedMemory(name=name) # reopen if needed Prevention
- Own the lifetime: one owner closes, after all consumers are done
- Grab shm.mmap once at startup and reuse the reference; don't re-access after close
- In multithreaded code, guard close() with the same lock as mmap access
When it happens
Trigger: Accessing shm.mmap after calling shm.close(); also in a __del__/destructor path or another thread that races with close().
Common situations: Forgetting close() was called in a cleanup/finally block; two processes/threads sharing the object where one closes it; storing a reference to the object beyond its intended lifetime.
Related errors
- Incorrect owner on pwfile: uid={shm.stats.st_uid} gid={shm.s
- Incorrect permissions on pwfile: 0o{mode:03o}
- ENAMETOOLONG
- 'size' must be a non-negative integer
- Cannot specify both name and size
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/cf5c751bab22db08.
Report an issue: GitHub.