Preflight
What happened?
ok diagnose health reports the server lock as corrupt for a file that is valid JSON:
[!] server-lock: server.lock is corrupt (unparseable or invalid pid)
→ Delete /opt/stacks/openknowledge/vault/.ok/local/server.lock and rerun.
The rejected value is "pid": 1 — which is exactly what ok start gets when it is the container entrypoint.
Three things follow from that, and the third is the damaging one:
- The port never gets written. The lock is created with
"port": 0. OK then tries to update it with the real port, re-reads the lock, rejects it as corrupt (invalid pid), and skips the update — so the port stays 0 for the life of the process.
ok ps goes blind. It reports No open-knowledge servers found, even when run inside the container where the server is answering HTTP 200.
ok sync silently no-ops. It falls back to Running sync directly (no live server) — and still prints ✓ sync complete.
In my case a container-hosted vault ran from 2026-09-09 to 2026-09-20 with ok sync reporting success on every run while never reaching the live server and never committing anything. Nothing in the output suggested a problem.
Expected: pid === 1 is treated as valid, since it is the normal PID for a container entrypoint; and if ok sync does fall back to the direct path, it says so loudly rather than printing ✓ sync complete.
Steps to reproduce
- Build an image that installs the CLI and runs
ok start as CMD, so it becomes PID 1:
FROM node:24-slim
RUN npm install -g @inkeep/open-knowledge@0.76.1
WORKDIR /vault
CMD ["ok", "start", "--port", "3011", "--bind", "0.0.0.0", \
"--external-url", "https://example.invalid", \
"--idle-shutdown", "off", "--no-open-browser"]
- Start the container against a vault and confirm the server is healthy:
curl -s -o /dev/null -w "%{http_code}" -H "Host: example.invalid" http://127.0.0.1:3011/ → 200
- Run
ok diagnose health → server-lock: server.lock is corrupt (unparseable or invalid pid)
- Run
ok ps → No open-knowledge servers found
- Run
ok sync → Running sync directly (no live server) … ✓ sync complete
- Delete
.ok/local/server.lock and restart → an identical pid: 1 / port: 0 lock is written again.
Platform
Linux
How did you install OpenKnowledge?
CLI (npm / npx)
Version
0.76.1
Logs, errors, or screenshots
The lock file — valid JSON, JSON.parse succeeds:
{
"pid": 1,
"hostname": "27b2a374c213",
"port": 0,
"worktreeRoot": "/opt/stacks/openknowledge/vault",
"kind": "interactive",
"capabilities": ["http", "ws", "ui"],
"protocolVersion": 2,
"runtimeVersion": "0.76.1"
}
Startup log:
WARN (process-lock): [server-lock] Corrupt lock at /opt/stacks/openknowledge/vault/.ok/local/server.lock during port update — skipping
lockPath: "/opt/stacks/openknowledge/vault/.ok/local/server.lock"
Ruled out: stale lock from a previous container (deleting it reproduces the same lock); malformed JSON (JSON.parse succeeds, port reads back as 0); wrong port value (hand-patching "port" to 3011 does not make ok ps find the server, because the pid is what fails validation); shadow-store corruption (this vault had 14 zero-byte objects in .git/ok/objects, repaired separately — git fsck is clean on both repos and git gc exits 0, and the lock behavior is unchanged).
Confirmed fix on my side: adding init: true to the compose service (tini as PID 1) makes ok a normal child process, and everything recovers immediately:
{ "pid": 6, "port": 3011, ... }
$ ok ps
DIRECTORY PORTS (API/UI) STATUS PID STARTED
/opt/stacks/openknowledge/vault 3011 / 3011 running 6 31s ago
$ ok sync
Triggering sync via running server (port 3011)
✓ sync triggered
Suggested changes
- Treat
pid === 1 as valid — process.pid returning 1 is not evidence of a corrupt lock.
- Distinguish "unparseable" from "implausible pid" in both the health check and the
process-lock warning; they have different causes and different fixes.
- Make
ok sync warn or fail when it falls back to the direct path for lack of a live server. The unconditional ✓ sync complete is what hid this for eleven days.
Preflight
What happened?
ok diagnose healthreports the server lock as corrupt for a file that is valid JSON:The rejected value is
"pid": 1— which is exactly whatok startgets when it is the container entrypoint.Three things follow from that, and the third is the damaging one:
"port": 0. OK then tries to update it with the real port, re-reads the lock, rejects it as corrupt (invalid pid), and skips the update — so the port stays0for the life of the process.ok psgoes blind. It reportsNo open-knowledge servers found, even when run inside the container where the server is answering HTTP 200.ok syncsilently no-ops. It falls back toRunning sync directly (no live server)— and still prints✓ sync complete.In my case a container-hosted vault ran from 2026-09-09 to 2026-09-20 with
ok syncreporting success on every run while never reaching the live server and never committing anything. Nothing in the output suggested a problem.Expected:
pid === 1is treated as valid, since it is the normal PID for a container entrypoint; and ifok syncdoes fall back to the direct path, it says so loudly rather than printing✓ sync complete.Steps to reproduce
ok startasCMD, so it becomes PID 1:curl -s -o /dev/null -w "%{http_code}" -H "Host: example.invalid" http://127.0.0.1:3011/→200ok diagnose health→server-lock: server.lock is corrupt (unparseable or invalid pid)ok ps→No open-knowledge servers foundok sync→Running sync directly (no live server)…✓ sync complete.ok/local/server.lockand restart → an identicalpid: 1/port: 0lock is written again.Platform
Linux
How did you install OpenKnowledge?
CLI (npm / npx)
Version
0.76.1
Logs, errors, or screenshots
The lock file — valid JSON,
JSON.parsesucceeds:{ "pid": 1, "hostname": "27b2a374c213", "port": 0, "worktreeRoot": "/opt/stacks/openknowledge/vault", "kind": "interactive", "capabilities": ["http", "ws", "ui"], "protocolVersion": 2, "runtimeVersion": "0.76.1" }Startup log:
Ruled out: stale lock from a previous container (deleting it reproduces the same lock); malformed JSON (
JSON.parsesucceeds,portreads back as0); wrong port value (hand-patching"port"to3011does not makeok psfind the server, because the pid is what fails validation); shadow-store corruption (this vault had 14 zero-byte objects in.git/ok/objects, repaired separately —git fsckis clean on both repos andgit gcexits 0, and the lock behavior is unchanged).Confirmed fix on my side: adding
init: trueto the compose service (tini as PID 1) makesoka normal child process, and everything recovers immediately:{ "pid": 6, "port": 3011, ... }Suggested changes
pid === 1as valid —process.pidreturning 1 is not evidence of a corrupt lock.process-lockwarning; they have different causes and different fixes.ok syncwarn or fail when it falls back to the direct path for lack of a live server. The unconditional✓ sync completeis what hid this for eleven days.