kovidgoyal/kitty · error · ValueError

Incorrect owner on pwfile: uid={shm.stats.st_uid} gid={shm.s

Error message

Incorrect owner on pwfile: uid={shm.stats.st_uid} gid={shm.stats.st_gid}

What it means

The ssh kitten passes passwords between the kitty process and the ssh wrapper over a POSIX shared-memory file, and read_data_from_shared_memory() validates that the shm file's uid/gid exactly match the current process's euid/egid before trusting it (and it unlinks it after opening). A mismatch raises ValueError('Incorrect owner on pwfile: ...'). This is a security check against another user planting or spoofing the pwfile.

Source

Thrown at kittens/ssh/utils.py:169

    db = json.dumps(data).encode('utf-8')
    with SharedMemory(size=len(db) + SharedMemory.num_bytes_for_size, prefix=prefix) as shm:
        shm.write_data_with_size(db)
        shm.flush()
        atexit.register(shm.close)  # keeps shm alive till exit
        get_boss().atexit.shm_unlink(shm.name)
    return shm.name


def read_data_from_shared_memory(shm_name: str) -> Any:
    import json
    import stat

    from kitty.shm import SharedMemory

    with SharedMemory(shm_name, readonly=True) as shm:
        shm.unlink()
        if shm.stats.st_uid != os.geteuid() or shm.stats.st_gid != os.getegid():
            raise ValueError(f'Incorrect owner on pwfile: uid={shm.stats.st_uid} gid={shm.stats.st_gid}')
        mode = stat.S_IMODE(shm.stats.st_mode)
        if mode != stat.S_IREAD | stat.S_IWRITE:
            raise ValueError(f'Incorrect permissions on pwfile: 0o{mode:03o}')
        return json.loads(shm.read_data_with_size())


def get_ssh_data(msgb: memoryview, request_id: str) -> Iterator[bytes | memoryview]:
    # Unfortunately we cannot use EOF (\x04) to flush the kernel line buffer
    # because ssh with controlmasters mangles EOF replacing it with null bytes
    from base64 import standard_b64decode

    yield b'\nKITTY_DATA_START\n'  # to discard leading data
    try:
        msg = standard_b64decode(msgb).decode('utf-8')
        md = dict(x.split('=', 1) for x in msg.split(':'))
        pw = md['pw']
        pwfilename = md['pwfile']
        rq_id = md['id']

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Avoid mixing privilege levels: run kitten ssh as the same user that owns the kitty session (don't sudo).
  2. Clear stale/foreign shm files: remove matching /dev/shm/kitty-* entries (or reboot/clean tmpfs) and retry.
  3. In containers, ensure /dev/shm is a private tmpfs with correct uid mapping (`--shm-size` and no shared /dev/shm between mismatched users).
  4. If reproducing in tests, create the SharedMemory file with the current process's uid/gid (the normal kitty flow does this automatically).

Example fix

# before
sudo -u otheruser kitten ssh host  # euid != shm owner -> ValueError: Incorrect owner on pwfile

# after
# run as the same user that owns the kitty session
kitten ssh host
Defensive patterns

Strategy: validation

Validate before calling

import os, stat

def shm_owner_ok(path_or_stats) -> bool:
    st = path_or_stats
    return st.st_uid == os.geteuid() and st.st_gid == os.getegid()

# before passing control to kitten ssh, ensure a clean /dev/shm
import glob
for p in glob.glob('/dev/shm/kitty*'):
    try:
        if not shm_owner_ok(os.stat(p)):
            os.unlink(p)
    except FileNotFoundError:
        pass

Try / catch

try:
    data = read_data_from_shared_memory(name)
except ValueError as e:
    if 'Incorrect owner on pwfile' in str(e):
        log.warning('stale/foreign shm file; clearing and retrying once')
        # remove the offending file and let kitty recreate it
    else:
        raise

Prevention

When it happens

Trigger: get_ssh_data() -> read_data_from_shared_memory(shm_name) when /dev/shm (or the tmpfs backing the shm) reports different st_uid/st_gid than os.geteuid()/os.getegid(). Typical causes: running under sudo/su where euid differs from the session that created the file, setuid/setgid wrappers, containers with ID-mapped or shared /dev/shm, or /dev/shm mounted from a host with different uid mapping.

Common situations: Running `kitten ssh` after sudo (root euid vs file owned by the user); container/Docker setups sharing /dev/shm between containers; NFS/overlay mounts for /dev/shm that rewrite ownership; multi-user systems where a stale or foreign shm file with the same name exists.

Related errors


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