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 = None

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Keep the SharedMemory object alive as long as any mmap/NumPy view derived from it is used; close only at the very end
  2. Audit cleanup paths (finally blocks, context managers) for premature close()
  3. Cache the mmap object before closing is possible only if you also keep the fd/mapping alive — instead, restructure so close happens last
  4. 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

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


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/cf5c751bab22db08. Report an issue: GitHub.