Error codes
DisplaySync surfaces errors as human-readable messages in the dashboard, mobile app, and kiosk logs. The product doesn't yet ship a fully-structured error-code taxonomy — a planned v2 enhancement — so this page is organized by category and message text rather than alphabetic code lookup.
If you're searching for a specific message you're seeing in the UI, Ctrl-F / Cmd-F is your friend — every message below is reproduced verbatim.
Authentication & registration
| Message | Meaning | Next step |
|---|---|---|
An account with this email already exists. Please sign in with your password and link Google in settings. | Trying to sign in with Google for an email that has a password account | Sign in with password, then link Google from Profile → Settings |
Email already in use | Registration with an email that's already registered | Sign in instead, or use a different email |
Current password is incorrect | Password change with wrong current password | Reset via "Forgot password" if you don't remember |
Email is already verified | Verification link clicked twice | Ignore — the second click is harmless |
RATE_LIMIT_EXCEEDED (429) | Too many requests in a short window | Wait 60 seconds and retry; persistent → contact support |
CSRF_TOKEN_INVALID / CSRF_VALIDATION_FAILED (403) | Stale dashboard session, or browser cookie issue | Hard refresh (Ctrl+Shift+R) the dashboard; if persistent, sign out and back in |
Handshake-flow rows activate when enabled
The four device_* / sign_not_connected / request_in_progress
rows below appear once your workspace has the link/claim handshake
enabled (backend env flag LINK_HANDSHAKE_ENABLED).
Pre-handshake workspaces won't surface these.
Sign claim & registration
| Message | HTTP | Activates | Meaning | Next step |
|---|---|---|---|---|
SHORTCODE_NOT_FOUND | 404 | — | The 6-char code doesn't match any pending sign | Re-scan the QR; if persistent, Sign won't claim |
This device is already claimed | 409 | — | Trying to claim a signId already in another org/event | Unregister from the other event first, or follow the hardware-swap workflow |
Sign is already linked and online | 400 | — | Linking a device to a sign record that already has a device attached | Unlink the existing device first |
Sign has been unregistered — hardware was claimed by a new sign | n/a (kiosk message) | — | Old kiosk learned its identity is now bound to a different physical device | The new claim wins — old kiosk shows QR for fresh re-claim |
device_no_ack | 504 | Handshake active | Kiosk did not ack the link/claim within timeout | "Sign didn't respond. Check it's online and retry." See Sign won't claim. |
device_load_failed | 400 | Handshake active | Kiosk acked failure during load. Sub-reasons: url_unreachable, url_load_failed, sign_timeout. | Verify the URL is reachable from the venue network; if URL is fine, retry — sign_timeout clears on retry. |
sign_not_connected | 400 | Handshake active | No active WebSocket session for the sign | Power-cycle the kiosk and retry. |
request_in_progress | 409 | Handshake active | Another claim/link request is in flight for this sign | Wait a few seconds and retry. |
Content & assignment
| Message | Meaning | Next step |
|---|---|---|
Content not found | The content ID referenced was deleted or never existed | Re-paste a valid URL into the sign's Assigned URL field |
Cannot update content for signs in an archived event | The event was archived; content edits are locked | Move sign to a non-archived event, or unarchive |
Command queued — sign will receive on reconnect | Sign offline; remote command was accepted but not yet delivered | Wait for sign to reconnect, or reboot it |
Content shows Unreachable in dashboard | Two consecutive HEAD checks failed against the assigned URL | See Content not loading |
Event & organization
| Message | Meaning | Next step |
|---|---|---|
Event not found | Stale URL or deleted event | Return to event list |
Cannot add signs to an archived event | Event is in archived state | Unarchive, or use a different event |
Cannot link signs to an archived event | Same as above for link operations | Same |
Cannot delete organization with existing events, signs, or content | Org cleanup safety guard | Delete or migrate child resources first |
Cannot remove the last owner. Assign another owner first. | Trying to remove the only org owner | Promote another member to owner, then retry |
A pending invitation already exists for this email | Inviting someone who already has an open invite | Resend the original or revoke and re-invite |
Permissions
When you don't have access to do something:
| Pattern | HTTP | Meaning |
|---|---|---|
Forbidden / Permission denied | 403 | Your role doesn't permit this action |
Organization access denied | 403 | You're not a member of this org |
Event access denied | 403 | You're not on this event's team and the event isn't visible to your org role |
Admin access required | 403 | The action requires the system admin role |
For the full permission matrix, see Roles & permissions.
Connection & networking (kiosk side)
These appear in the kiosk's sign.log rather than the dashboard:
| Log signature | Meaning | Next step |
|---|---|---|
[ERROR] WebSocket connection failed: ECONNREFUSED | Backend unreachable | Verify firewall, see Network requirements |
[ERROR] WebSocket error: ENETUNREACH | No route to backend (LAN/WAN dropped) | Check venue uplink |
[ERROR] Hostname not found | DNS failure | Check venue DNS, or set static |
[ERROR] certificate has expired | Kiosk clock is wrong | NTP sync: w32tm /resync |
[INFO] Attempting reconnection... (repeating) | Constant reconnect cycle | See Sign shows offline → flapping |
HTTP status codes used by the API
| Code | When you see it |
|---|---|
| 200 OK | Normal success |
| 201 Created | Resource created (sign claim, event create, etc.) |
| 204 No Content | Successful delete, no body |
| 400 Bad Request | Validation failed — message contains specifics |
| 401 Unauthorized | Not signed in, or session expired |
| 403 Forbidden | Signed in, but lack permission |
| 404 Not Found | Resource doesn't exist or you can't see it (404 vs 403 is sometimes deliberate to avoid leaking existence) |
| 409 Conflict | State conflict — already claimed, already linked, etc. |
| 429 Too Many Requests | Rate limited (auth routes are stricter). Wait 60s and retry; persistent 429s indicate a misconfigured client. |
| 500 Internal Server Error | Unexpected backend failure — contact support if persistent |
| 502 Bad Gateway | Upstream Fly proxy infrastructure error; not application code. If persistent, check Fly status, not backend logs. |
| 503 Service Unavailable | Health endpoints emit 503 when DB is down or Redis is degraded. Also returned when assigning content to an offline sign — the assignment is recorded but the live broadcast fails; the assignment delivers when the sign reconnects. |
| 504 Gateway Timeout | Handshake timeout from the acknowledged link/claim flow (device_no_ack) — see Sign claim & registration. |
Sentry tags and context
Errors that bubble up to Sentry from a kiosk carry one tag and a sign context object for triage:
| Field | Type | Value | Meaning |
|---|---|---|---|
sign.id | tag | UUID | The kiosk that emitted the error |
signId, organizationId, eventId | context (in sign) | UUIDs | Owning org and active event for the kiosk |
appVersion | tag | semver | Desktop sign version |
environment | tag | production / staging | Deploy target |
When opening a support request related to an error, including the kiosk's signId lets us correlate to Sentry events directly.
Future: structured error codes
A v2 enhancement will introduce structured error codes (E_SIGN_CLAIM_*, E_CONTENT_*, etc.) that decouple message text from machine-readable identifiers. Until then, the messages above are the source of truth and any error-handling code should match on text rather than codes.
See also
- Getting support — what to capture when an error doesn't have an obvious fix
- Troubleshooting — symptom-indexed playbooks for common failures
- Sign states — state-related errors are state transitions