Skip to content

Server lock rejected as corrupt when ok start runs as PID 1 (Docker): ok ps blind, ok sync silently no-ops #1733

Description

@Danvegamo

Preflight

  • I searched existing issues and this isn't a duplicate
  • I'm on the latest version (or I've noted my version below)

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:

  1. 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.
  2. ok ps goes blind. It reports No open-knowledge servers found, even when run inside the container where the server is answering HTTP 200.
  3. 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

  1. 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"]
  2. 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
  3. Run ok diagnose health → server-lock: server.lock is corrupt (unparseable or invalid pid)
  4. Run ok ps → No open-knowledge servers found
  5. Run ok sync → Running sync directly (no live server) … ✓ sync complete
  6. 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

  1. Treat pid === 1 as valid — process.pid returning 1 is not evidence of a corrupt lock.
  2. Distinguish "unparseable" from "implausible pid" in both the health check and the process-lock warning; they have different causes and different fixes.
  3. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions