## TL;DR
The Jupyter server writes one small JSON file per kernel into its runtime directory, and when that directory is read-only or owned by a different user every kernel launch fails with PermissionError. Check the directory with `jupyter --runtime-dir` and `ls -ld` on it. Either fix ownership with chown or set the `JUPYTER_RUNTIME_DIR` environment variable to a directory you own, then restart the server.

```text
PermissionError: jupyter server failed to write runtime json file
```

## Use this when
- Kernel launches fail with PermissionError mentioning the runtime json file.
- The server runs as a different user than the one who owns the runtime dir (sudo installs, containers, shared machines).
- `ls -ld` on the runtime dir shows it is not writable by the server user.

## Not for this skill when
- The error is about port 8888 being in use. That is a port conflict, not permissions.
- Notebooks fail to save. That is the notebook dir permissions, a different path.

## Steps
1. Find the runtime dir: `jupyter --runtime-dir`. Verify: you have the exact path.
2. Check ownership and writability: `ls -ld [runtime-dir]` and `touch [runtime-dir]/writetest && rm [runtime-dir]/writetest`. Verify: you see who owns it and whether writes work.
3. If you administer the machine, fix ownership: `chown -R [user]:[group] [runtime-dir]`. Verify: the touch test now succeeds.
4. If you cannot change ownership, redirect it: `export JUPYTER_RUNTIME_DIR=[writable-dir]` before starting the server. Verify: `jupyter --runtime-dir` prints the new path.
5. Restart the server and launch a kernel. Verify: no PermissionError and a new json file appears in the runtime dir.

## Variant phrasings
### jupyter runtime dir permission denied
Short form. Ownership or redirect, your choice.

### failed to write server json jupyter
Log-style phrasing. Same runtime-dir fix.

### jupyter kernel permissionerror runtime
Kernel-side phrasing. The server writes the file, so fix the server's dir.

Compatibility: All Jupyter server versions. JUPYTER_RUNTIME_DIR is honored by notebook 6/7 and JupyterLab 3/4.

## Why it happens
The runtime directory defaults to a per-user path, but servers started with sudo, inside containers with volume mounts, or on shared machines often run as a user that does not own it. The server only discovers this when it tries to write the kernel's connection file, so everything looks fine until the first kernel launch, which then fails with a bare PermissionError.

## Edge cases / pitfalls
- Setting the env var in your shell but starting the server from a desktop launcher or systemd unit does not propagate it. Set it where the server actually starts.
- A full disk produces the same PermissionError text via a different errno. Check `df -h` if ownership looks right.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_uXJQSAkvKCKxjEExn7hGPQ
