Skip to content

fix(docker/tui): chown ui-tui to hermes + actionable build error (#20500)#20509

Open
Beandon13 wants to merge 1 commit into
NousResearch:mainfrom
Beandon13:fix/hermes-20500-tui-eacces-docker
Open

fix(docker/tui): chown ui-tui to hermes + actionable build error (#20500)#20509
Beandon13 wants to merge 1 commit into
NousResearch:mainfrom
Beandon13:fix/hermes-20500-tui-eacces-docker

Conversation

@Beandon13

Copy link
Copy Markdown
Contributor

Summary

Fixes #20500 — the dashboard's embedded Chat tab fails on first connect in the official Docker image with the unhelpful banner "Chat unavailable: 1".

Root cause (per the issue's reproduction)

Three compounding factors:

  1. Dockerfile runs the TUI build as root: COPY --chown=hermes:hermes . . chowns the source tree, but the RUN cd ui-tui && npm run build step executes as root (no preceding USER directive). The artifacts written into ui-tui/dist/ and ui-tui/packages/hermes-ink/dist/ end up root-owned.
  2. At runtime the entrypoint drops privileges via gosu hermes. When _make_tui_argv decides the bundle is stale and reruns npm run build, esbuild fails with EACCES on the root-owned dist dirs.
  3. _make_tui_argv calls sys.exit(1). web_server.pty_ws catches the resulting SystemExit and renders Chat unavailable: {exc}str(SystemExit(1)) is just \"1\", hence the unhelpful banner.

Fix

Three coordinated changes (each independent, but together close the bug for both new images and remapped-UID deployments):

  1. Dockerfile — chown /opt/hermes/ui-tui to hermes:hermes immediately after npm run build. Survives image rebuilds, so users no longer have to chown manually after every docker compose pull. (Implements suggestion 1 in the issue.)
  2. docker/entrypoint.sh — defensive recursive chown of $INSTALL_DIR/ui-tui while still running as root, before the gosu drop. Handles the HERMES_UID remap case where the Dockerfile's build-time chown is for UID 10000 but the runtime user has a different UID. Silent failure on rootless containers where chown isn't permitted. (Implements suggestion 2.)
  3. hermes_cli/main.py — replace bare sys.exit(1) in _make_tui_argv with raise SystemExit(\"<reason>\") so pty_ws shows an actionable message. EACCES in the build output is detected and surfaced explicitly with the chown remedy and a pointer to issue Dashboard Chat tab fails with EACCES in Docker image — /opt/hermes/ui-tui is root-owned but dashboard runs as hermes #20500. (Implements the bonus surfacing improvement.)

Test plan

Compatibility

  • Dockerfile chown adds ~1s to build time; cheap on the file count in ui-tui/.
  • Entrypoint chown is no-op on already-correctly-owned trees.
  • SystemExit(\"<str>\") returns a non-zero exit code (the str), so launchers that key on returncode != 0 still see a non-zero exit.

…sResearch#20500)

Three coordinated changes for the dashboard "Chat unavailable: 1"
banner reported in NousResearch#20500:

1. Dockerfile: chown ``/opt/hermes/ui-tui`` to ``hermes:hermes`` after
   the build step.  ``COPY --chown=hermes:hermes . .`` runs before the
   build, but ``RUN cd ui-tui && npm run build`` executes as root and
   leaves ``ui-tui/dist/`` and ``ui-tui/packages/hermes-ink/dist/``
   root-owned.  When ``_tui_build_needed`` later trips and esbuild
   tries to rewrite those dist files as the ``hermes`` user, it fails
   with EACCES.

2. ``docker/entrypoint.sh``: defensive recursive chown of
   ``$INSTALL_DIR/ui-tui`` while still running as root, before the
   gosu drop.  Handles the case where ``HERMES_UID`` remaps the
   runtime hermes UID — the Dockerfile's build-time chown was for the
   image-default UID 10000, so the tree appears foreign-owned to the
   remapped runtime user.  Silent failure on rootless containers
   where chown isn't permitted.

3. ``hermes_cli/main.py``: replace ``sys.exit(1)`` in ``_make_tui_argv``
   with ``raise SystemExit("<reason>")`` so ``pty_ws`` (which renders
   ``Chat unavailable: {exc}``) shows an actionable message instead of
   a bare ``Chat unavailable: 1``.  EACCES in the build output is
   detected and surfaced explicitly with the chown remedy.

Adds tests/hermes_cli/test_tui_build_failure_message.py covering both
the EACCES-detection path and the generic build-failure path.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists area/docker Docker image, Compose, packaging comp/tui Terminal UI (ui-tui/ + tui_gateway/) labels May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docker Docker image, Compose, packaging comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dashboard Chat tab fails with EACCES in Docker image — /opt/hermes/ui-tui is root-owned but dashboard runs as hermes

2 participants