From 05a98efe57b3d83d22b66710e5fdd5b7a805a072 Mon Sep 17 00:00:00 2001 From: Oier Bravo Urtasun Date: Thu, 23 Jul 2026 02:38:13 +0200 Subject: [PATCH] docs(migration): fresh-world kubejs root-owned crash-loop + fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a fresh mc_data volume the minecraft service crash-loops with "AccessDeniedException: /data/kubejs/config" (ConsoleJS.STARTUP null NPE): Docker auto-creates the bind-mount parent /data/kubejs as root:root, but the itzg container runs as uid 1000, so KubeJS can't create its writable siblings (config/cache/generated/logs). Only bites fresh worlds — cochi's aged volume predates the ro submounts and is already 1000-owned. Fix (durable): chown 1000:1000 /data/kubejs once, then restart. - plan/22-migration.md: Troubleshooting section with symptom + fix. - migrate-import.sh: manual tail now flags it with the exact commands. Hit + resolved during the cochi->oxps migration. Co-Authored-By: Claude Opus 4.8 (1M context) --- plan/22-migration.md | 35 +++++++++++++++++++++++++++++++++++ tooling/migrate-import.sh | 8 ++++++++ 2 files changed, 43 insertions(+) diff --git a/plan/22-migration.md b/plan/22-migration.md index 6f311ef..9d0506d 100644 --- a/plan/22-migration.md +++ b/plan/22-migration.md @@ -153,6 +153,41 @@ cochi's copy. Rolling back to cochi then **silently loses** those new accounts/skins. Safe for hours as a fallback; not for weeks. If you must roll back after real use, re-export from oxps and re-import onto cochi first. +## Troubleshooting + +### minecraft crash-loops on a fresh host: `AccessDeniedException: /data/kubejs/config` + +Symptom (in `docker compose logs minecraft`), restarting every ~15s: + +``` +java.nio.file.AccessDeniedException: /data/kubejs/config +Caused by: NullPointerException: Cannot invoke "...ConsoleJS.error(...)" + because "dev.latvian.mods.kubejs.script.ConsoleJS.STARTUP" is null +``` + +**Cause.** The compose file bind-mounts the kubejs *source* subdirs read-only +(`server_scripts`, `startup_scripts`, `data`, `assets`). To place those mounts, +Docker auto-creates their parent `/data/kubejs` — and on a **fresh `mc_data` +volume** it creates it as **root:root**. The itzg container runs as **uid 1000**, +so KubeJS can't create its writable siblings (`config/`, `cache/`, `generated/`, +`logs/`) → init aborts → `ConsoleJS.STARTUP` stays null → NPE → exit 1. + +This only bites a **fresh world** (migration, new host, wiped `mc_data`). On an +aged host like cochi `/data/kubejs` predates the ro submounts and is already +1000-owned, so it never surfaced there. + +**Fix** — chown the dir to 1000 once (durable; survives restarts): + +```bash +docker compose stop minecraft +docker run --rm -v _mc_data:/data alpine chown 1000:1000 /data/kubejs +docker compose up -d minecraft +``` + +`` is the checkout dir basename (e.g. `ulicraft-server`). Distinct from +the "don't mount the whole kubejs dir ro" gotcha in `plan/05-minecraft.md` — same +mod, different trigger (ownership of the auto-created parent, not a ro root). + ## Re-running / testing Everything is idempotent-ish and safe to rehearse: diff --git a/tooling/migrate-import.sh b/tooling/migrate-import.sh index b8db4b2..1ef0e73 100755 --- a/tooling/migrate-import.sh +++ b/tooling/migrate-import.sh @@ -176,6 +176,14 @@ Remaining manual steps (see plan/22-migration.md for detail): 7. Bring it up: ./update-all.sh --hard 8. Re-op players once they've joined: docker compose exec minecraft rcon-cli op +Fresh-world gotcha: if minecraft crash-loops on a fresh mc_data with + "AccessDeniedException: /data/kubejs/config" (ConsoleJS.STARTUP null), Docker + created /data/kubejs as root while the container runs as uid 1000. Fix once: + docker compose stop minecraft + docker run --rm -v ${PROJ}_mc_data:/data alpine chown 1000:1000 /data/kubejs + docker compose up -d minecraft + Details: plan/22-migration.md (Troubleshooting). + Rollback note: same domain means DNS points at ONE host. Once a player registers or changes a skin here, this drasl.db diverges from cochi — rolling back to cochi silently loses those changes. Keep the fallback window short.