Errors and recovery
Handle plan limits, browser startup, and human handoff. Use the returned detail instead of assumed error codes.
Read the response detail
The session client parses JSON when possible. For failures, it uses detail when present. Otherwise it includes the response content.
No complete server error schema is published. Preserve the HTTP status and a redacted error message. Do not depend on invented machine-readable error names.
const response = await fetch("https://skill.legba.xyz/api/v1/sessions/current", {
headers: { Authorization: "Bearer " + process.env.LEGBA_API_KEY },
});
const raw = await response.text();
let body;
try { body = JSON.parse(raw); } catch { body = raw; }
if (!response.ok) {
const detail = body?.detail ?? body;
throw new Error(response.status + ": " + JSON.stringify(detail));
}
console.log(body.session ? "Session exists" : "No active session");402: plan limit
A 402 response requires a plan decision. The session client prints UPGRADE NEEDED and exits with code 4. Show the returned explanation and upgrade link to the user.
Do not retry unchanged requests. Hosted browsers are excluded from the Free skill plan. The returned limit determines the next action.
Browser startup failures
The published client retries certain startup failures. These include HTTP 502, 503, and 504. It also recognizes these response messages:
still startingbridge_unreachablenot answering
Automatic retries apply to go, read, and shot. The client waits 5 seconds between attempts. Its startup retry window is 150 seconds.
Clicks and typing do not use that automatic loop. Inspect readiness before repeating an action. Avoid replaying actions whose outcome is uncertain.
Session and control conflicts
Failure and next action
| Parameter | Type | Description |
|---|---|---|
No active session | Client check | Create a session before sending browser actions. |
A routing session is active | Client check | Routing sessions cannot receive browser actions. Finish the existing task before opening a browser. |
A session already exists | Account capacity | Inspect current state. Reuse appropriate work or end only a session you own. |
Human control is active | Write refusal | Wait for the person to finish. Do not force a resume while they are working. |
Human-operated browser | Unsupported action | Give its view link to the user. Use browser: agent when automation is required. |
The source does not assign HTTP codes to every condition. Read the actual response instead of guessing.
Local script exit codes
Documented exit codes
| Parameter | Type | Description |
|---|---|---|
1 | Session client | General failure, including missing credentials or failed API requests. |
3 | render.mjs, antibot.py | Missing Playwright dependency in render.mjs; Camoufox installation or startup failure in antibot.py. Other Chromium launch failures are not normalized to exit 3. |
4 | legba-session.mjs | Plan refusal. Stop and show the returned limit. |
5 | antibot.py | The requested page did not load past a browser check. Do not treat the returned interstitial as page content. |
For legacy pool health calls, 410 or 502 means provision a fresh route. That rule belongs to the pool helper, not session creation.
See diagnostics for a safe support report.