Errors
Every failure in Beam carries a machine-readable reason beside its message, on both sides of the wire. Match on the reason; show the message.
PHP: BeamException
RealRashid\Beam\Exceptions\BeamException — $e->reason() is the string, $e->errorCode the ErrorCode enum.
| Reason | Thrown by | Means |
|---|---|---|
FORBIDDEN | ring(), $room->token(), the routes | a gate refused, or a token was presented by the wrong user |
EXPIRED | Token::parse(), the routes | the token's expiresAt has passed |
TAMPERED | Token::parse(), the routes | the token does not decrypt or verify |
PROTOCOL_MISMATCH | Token::parse() | the token was minted by a different Beam version than the one reading it |
NOT_FOUND | Beam::findOrFail(), Beam::room()->findOrFail(), POST /beam/transfers | no such live call, room or user — find() returns null instead, as it does everywhere in Laravel |
TURN_UNAVAILABLE | TURN drivers | the vendor's API refused or timed out; TurnUnavailable fires and the call proceeds on STUN |
INVALID_CONFIGURATION | builders, drivers, link() | a room name, a driver key or a missing route |
GATEWAY_ERROR | HTTP TURN drivers | the vendor answered with something that was not credentials |
PUSH_UNAVAILABLE | the push routes | Web Push is not configured on this server |
ROOM_FULL | $room->token() | two people are already in that room; a Beam room carries two |
Thrown inside a request — a gate refusing ring() in your controller, say — a BeamException renders itself as JSON, {"message": "…", "reason": "…"}, with the status its reason implies: 403 for FORBIDDEN, 401 for EXPIRED, TAMPERED and PROTOCOL_MISMATCH, 404 for NOT_FOUND, 503 for TURN_UNAVAILABLE, GATEWAY_ERROR and PUSH_UNAVAILABLE. An INVALID_CONFIGURATION in a browser request gets Laravel's normal error page, because that one is for you.
HTTP responses
Beam's routes answer JSON: {"message": "…", "reason": "…"}.
| Status | Reason | When |
|---|---|---|
| 401 | MISSING_TOKEN | no token on a route that needs one |
| 401 | EXPIRED, TAMPERED, PROTOCOL_MISMATCH | the token failed to parse |
| 403 | FORBIDDEN | the token is another user's, names another channel, or the user is not a participant of that live call |
| 404 | NOT_FOUND | the call, room or user does not exist |
| 409 | ROOM_FULL | a third person asked for a token to a room that already has two |
| 413 | TOO_LARGE | a file offer over transfer.max_bytes |
| 422 | (validation) | a malformed signal |
| 503 | PUSH_UNAVAILABLE | the VAPID public key was asked for and there is none |
JavaScript: BeamError
Beam.join() and the controls reject with, and call.on('error') receives, a BeamError with .reason and .message.
| Reason | Means | Usually |
|---|---|---|
permission-denied | the camera, microphone, screen or notifications were refused | show how to allow them; a call cannot start without media |
no-device | no camera or microphone was found | offer audio-only |
media-failed | the device could not be opened, or the page is not a secure context | check HTTPS; another app may hold the camera |
screen-unavailable | this browser has no screen picker (Android, iOS) or the stream carried no video | hide the share button — platform.supportsDisplayMedia() |
protocol-mismatch | the token was minted by a different Beam version than the client | a cached beam.js; beam:doctor checks it |
expired | the token's time has passed | fetch a fresh page |
malformed | the token does not decode | it was edited or truncated |
signaling-failed | the server refused a signal, or Echo is missing | the response's reason says which; Beam.configure({ echo }) |
turn-unavailable | the token carried no usable relay | the call may still connect on STUN |
connection-failed | negotiation failed, or a transfer's hash did not match | retry; report |
declined | the other side declined the call or the file | show it |
timeout | nobody answered in time | show it |
autoplay-blocked | the browser refused to play the remote stream without a tap | say "tap to hear"; Beam retries on the next tap |
unsupported | this browser lacks the feature (setSpeaker() on Safari) | hide the control |
room-full | a third participant is signalling on a room's channel; their messages are being ignored | say the room is busy — your server refuses the third token, so this is the rare case of one already in flight |
A call that ends carries a reason too, on the ended event and in CallEnded. Every one Beam itself uses:
| Reason | Who ends it |
|---|---|
hangup | either side called hangUp() |
remote-hangup | the other side hung up and this browser heard the bye |
navigated | this browser left the page or unmounted the component |
declined | the callee declined the ring |
timeout | nobody answered before timeout seconds |
connection-lost | recovery ran out — the browser's own reconnect_timeout, or the server finding nothing has heartbeated for three intervals |
server | $call->end() on the server with no reason given |
closed | $room->close() |
Anything else is a string your own code passed to end() or decline().
Made with ❤️ from Pakistan