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 |
Sign is offline — commands cannot be sent. | Not an error response — the sign detail page's Commands card disables every button while the sign is offline and shows this as the reason | Get the sign back online (Sign shows offline), then re-issue. In a bulk wave, offline signs resolve as Skipped rather than blocking the wave. |
Requires technician role or higher on this event. | Same card, different block — your event role can't send commands | Ask an event manager to assign you technician or above (Roles & permissions) |
UNSUPPORTED_MEDIA_TYPE (415) | An upload was rejected because the file type isn't one DisplaySync accepts — usually a mis-picked file (a PDF where an image was wanted, a .heic from a phone) | Re-pick the file in a supported format and upload again |
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 event with registered signs (409) | Event cleanup safety guard — deleting the event would orphan its signs | Remove or unregister the event's signs first (or move them to another event), then retry. The dashboard's delete dialog blocks the confirm and names the count before you get this far. Archiving has no such restriction. |
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, or a delete blocked by children still referencing the record (see Event & organization) |
| 415 Unsupported Media Type | An upload's file type isn't accepted. Re-pick the file in a supported format. |
| 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 the database is down. 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