hermes - 💡(How to fix) Fix Signal gateway setup: four pitfalls undocumented in signal.md (Java 25 pinning, ACI UUID auth, 409 stuck-state recovery, bbernhard incompatibility)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

UnsupportedClassVersionError: org/asamk/signal/Main has been compiled by a more recent version of the Java Runtime (class file version 69.0), this version of the Java Runtime only recognizes class file versions up to 65.0

Root Cause

Worth flagging explicitly because every Google result for "signal docker setup" points at bbernhard's REST wrapper. The adapter (gateway/platforms/signal.py) speaks to signal-cli's native --http daemon and expects:

Code Example

UnsupportedClassVersionError: org/asamk/signal/Main has been compiled by a more recent version of the Java Runtime (class file version 69.0), this version of the Java Runtime only recognizes class file versions up to 65.0

---

Verify error: StatusCode: 499
DeprecatedVersionException

---

sudo mkdir -p /opt/java
curl -fsSL "https://api.adoptium.net/v3/binary/latest/25/ga/linux/x64/jre/hotspot/normal/eclipse?project=jdk" \
  | sudo tar xz -C /opt/java
sudo ln -sf /opt/java/jdk-25* /opt/java/current

---

WARNING gateway.run: Unauthorized user: 00000000-aaaa-bbbb-cccc-000000000000 (DisplayName) on signal

---

SIGNAL_ALLOWED_USERS=+49BOT,+49USER,<aci-uuid>
RAW_BUFFERClick to expand / collapse

While setting up the Signal adapter on a fresh Debian 13 / WSL2 install I hit three failure modes that aren't covered in website/docs/user-guide/messaging/signal.md. All three cost ~30 min each to diagnose. Posting them so the docs (or the adapter) can address them — happy to follow up with a doc PR if useful.

1. signal-cli 0.14.x requires Java 25 — Debian's openjdk-21-jre-headless is too old

Trying to run signal-cli from 0.14.x on Java 21 produces, at the verify step:

UnsupportedClassVersionError: org/asamk/signal/Main has been compiled by a more recent version of the Java Runtime (class file version 69.0), this version of the Java Runtime only recognizes class file versions up to 65.0

Falling back to signal-cli 0.13.x doesn't help — Signal's servers reject all pre-0.14 clients as of May 2026 with:

Verify error: StatusCode: 499
DeprecatedVersionException

Suggested doc fix: explicitly pin Adoptium Temurin 25 (or newer) and warn that distro-packaged signal-cli / openjdk-21 is not usable. Concrete recipe that worked:

sudo mkdir -p /opt/java
curl -fsSL "https://api.adoptium.net/v3/binary/latest/25/ga/linux/x64/jre/hotspot/normal/eclipse?project=jdk" \
  | sudo tar xz -C /opt/java
sudo ln -sf /opt/java/jdk-25* /opt/java/current

…and in the systemd unit, pin Environment=JAVA_HOME=/opt/java/current so the daemon doesn't fall back to the system JRE.

2. SIGNAL_ALLOWED_USERS must include the sender's ACI UUID, not just their E.164 number

Signal's Phone Number Privacy (default since ~2023) hides the sender's E.164 behind their ACI UUID for inbound messages. The Hermes adapter receives the UUID and compares it literally against SIGNAL_ALLOWED_USERS, so a phone-number-only allowlist never matches real DMs:

WARNING gateway.run: Unauthorized user: 00000000-aaaa-bbbb-cccc-000000000000 (DisplayName) on signal

…even though +49USER_PERSONAL was in the env list. The fix is to read the UUID from the warning line and add it alongside the number:

SIGNAL_ALLOWED_USERS=+49BOT,+49USER,<aci-uuid>

The existing doc only shows the phone-number form, so users following the example get a healthy-looking adapter that silently rejects every incoming message.

Suggested doc fix: call this out explicitly, and ideally have the adapter log the both identifiers in the "Unauthorized user" warning so the user can copy/paste straight into the allowlist (today the UUID is logged but it isn't obvious that it belongs in SIGNAL_ALLOWED_USERS).

3. 409 AlreadyVerifiedException during signal-cli register is unrecoverable from signal-cli alone

Happens when a previous registration attempt (e.g. via bbernhard/signal-cli-rest-api, or an interrupted captcha→verify flow) left the number in a verified-but-uninitialized state server-side. signal-cli register --reregister hits the same endpoint and returns the same 409. signal-cli verify <code> with no active session returns "No registration verification session active".

Confirmed working recovery: put the SIM in a phone, install the Signal mobile app, complete normal registration as primary device, then Settings → Account → Delete Account in the app. This clears server-side state. After that, signal-cli register --captcha works normally.

Suggested doc fix: document this recovery path — without it the only options users find online are "wait 24h" (unreliable, undocumented session lifetime) or "try a different number" (often impossible).

4. bbernhard/signal-cli-rest-api is API-incompatible with the Hermes adapter — and looks like it works

Worth flagging explicitly because every Google result for "signal docker setup" points at bbernhard's REST wrapper. The adapter (gateway/platforms/signal.py) speaks to signal-cli's native --http daemon and expects:

EndpointMethodPurpose
/api/v1/checkGETHealth (HTTP 200)
/api/v1/eventsGET SSEInbound stream
/api/v1/rpcPOSTJSON-RPC

bbernhard/signal-cli-rest-api exposes /v1/about, /v2/send, /v1/health etc. — completely different. Trying to bridge with a Caddy reverse-proxy gets the health check and version call green but the SSE event JSON shape and the JSON-RPC body schema also differ, so messages never deliver. Symptom: Signal SSE: connected log line repeats every ~2 seconds in gateway.log.

Suggested doc fix: open signal.md with a one-line "do not use bbernhard/signal-cli-rest-api — the API is incompatible" before the install instructions. That alone would have saved me a couple of hours.


Environment: Debian 13 (trixie), WSL2, hermes user installer at ~/.hermes/hermes-agent, gateway running as system service, signal-cli 0.14.4.1 via systemd user service. Happy to send a docs PR covering all four points if it's wanted.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING