Skip to main content

Semantic Exit Codes

bdg uses semantic exit codes that communicate actionable information, not just success/failure. This enables agents to make programmatic decisions about retries, error recovery, and escalation.
bdg dom click "#missing-button"
echo $?  # 83 (RESOURCE_NOT_FOUND)

bdg dom fill "input" "invalid"  # Validation error
echo $?  # 81 (INVALID_ARGUMENTS)

bdg cdp Network.timeout --params '{}'
echo $?  # 102 (CDP_TIMEOUT)

Exit Code Ranges

Exit codes follow semantic ranges for predictable automation:
0        Success (command completed successfully)
Stability guarantee: Exit code values are part of bdg’s stable public API and will not change in minor versions

Complete Exit Code Registry

Success Codes

CodeNameDescriptionAgent Action
0SUCCESSOperation completed successfullyProceed to next step

User Error Codes (80-99)

CodeNameDescriptionAgent Action
80INVALID_URLInvalid URL format or unreachable URLFix URL format, don’t retry
81INVALID_ARGUMENTSInvalid command-line arguments or optionsFix arguments, don’t retry
82PERMISSION_DENIEDInsufficient permissions for operationCheck permissions, escalate
83RESOURCE_NOT_FOUNDRequested resource not found (session, element, etc.)Verify resource exists, try alternate
84RESOURCE_ALREADY_EXISTSResource already exists (duplicate session, etc.)Use existing resource or clean up
85RESOURCE_BUSYResource is locked or busyWait and retry with backoff
86DAEMON_ALREADY_RUNNINGDaemon is already runningUse existing daemon or cleanup
87STALE_CACHECache invalidated by navigation or DOM changesRe-run query to refresh cache
88NO_FORMS_FOUNDNo forms discovered on the pageVerify page loaded, check selectors
89FORM_IN_IFRAMEForm is inside an iframe (not yet supported)Use CDP to access iframe context

Software Error Codes (100-119)

CodeNameDescriptionAgent Action
100CHROME_LAUNCH_FAILUREChrome browser failed to launchRetry once, then escalate
101CDP_CONNECTION_FAILUREFailed to connect to Chrome DevTools ProtocolRetry with backoff, check Chrome
102CDP_TIMEOUTCDP operation timed outRetry with longer timeout
103SESSION_FILE_ERRORSession file read/write errorCheck file permissions, cleanup
104UNHANDLED_EXCEPTIONUnhandled exception in codeReport bug, don’t retry
105SIGNAL_HANDLER_ERRORSignal handler errorReport bug, don’t retry
110SOFTWARE_ERRORGeneric software error (use specific codes when possible)Report bug, don’t retry
Use ranges for category detection: 80-99 = user error, 100-119 = software error

JSON Error Output

All errors are returned in a structured format when using --json:
bdg dom click "#nonexistent" --json
{
  "version": "0.6.0",
  "success": false,
  "error": "Element not found: #nonexistent",
  "exitCode": 83,
  "suggestion": "Verify selector exists on page. Use 'bdg dom query \"#nonexistent\"' to test selector."
}

Error Response Schema

interface BdgErrorResponse {
  version: string;          // bdg version
  success: false;           // Always false for errors
  error: string;            // Human-readable error message
  exitCode: number;         // Semantic exit code (80-119)
  suggestion?: string;      // Optional recovery suggestion
  details?: {               // Optional additional context
    [key: string]: unknown;
  };
}

Recovery Suggestions

Every error includes actionable recovery suggestions:

Example 1: Element Not Found

bdg dom click "button.submit"
{
  "success": false,
  "error": "Element not found: button.submit",
  "exitCode": 83,
  "suggestion": "Verify selector exists on page. Use 'bdg dom query \"button.submit\"' to test selector."
}

Example 2: Stale Cache

bdg dom get 0  # After navigation invalidated cache
{
  "success": false,
  "error": "Element at index 0 not accessible",
  "exitCode": 87,
  "suggestion": "Re-run query to refresh cache. DOM was modified or page navigated."
}

Example 3: Invalid CDP Parameters

bdg cdp Network.setCookie --params '{"name":"test"}'
{
  "success": false,
  "error": "Invalid CDP parameters: missing required field 'url'",
  "exitCode": 81,
  "suggestion": "Use 'bdg cdp Network.setCookie --describe' to see required parameters.",
  "details": {
    "missing": ["url"],
    "provided": ["name"]
  }
}

Example 4: Session Not Found

bdg dom query "button"  # No active session
{
  "success": false,
  "error": "No active session found",
  "exitCode": 83,
  "suggestion": "Start a session with: bdg <url>"
}
Suggestions are executable commands - agents can run them directly

Agent Decision Logic

Agents should implement retry logic based on exit code ranges:
const result = await exec('bdg dom click "button"');
const exitCode = result.exitCode;

if (exitCode === 0) {
  // Success - proceed to next step
  return result.data;
}

if (exitCode >= 80 && exitCode <= 89) {
  // User/input error - don't retry, fix input
  if (exitCode === 83) {
    // RESOURCE_NOT_FOUND - try alternate selector
    return tryAlternateSelector();
  }
  if (exitCode === 81) {
    // INVALID_ARGUMENTS - fix arguments
    return fixArguments();
  }
}

if (exitCode >= 90 && exitCode <= 99) {
  // Resource/state error - may be recoverable
  if (exitCode === 87) {
    // STALE_CACHE - re-run query
    return refreshCacheAndRetry();
  }
  if (exitCode === 85) {
    // RESOURCE_BUSY - wait and retry
    await sleep(1000);
    return retry();
  }
}

if (exitCode >= 100 && exitCode <= 109) {
  // Integration/external error - retry with backoff
  if (exitCode === 102) {
    // CDP_TIMEOUT - retry with longer timeout
    return retryWithLongerTimeout();
  }
  // Retry with exponential backoff
  return retryWithBackoff();
}

if (exitCode >= 110 && exitCode <= 119) {
  // Internal software error - don't retry, report bug
  return reportBug(result.error);
}

Error Context in stderr

Even without --json, errors provide structured context:
bdg dom click "#missing" 2>&1
Error: Element not found: #missing

Suggestion: Verify selector exists on page. Use 'bdg dom query "#missing"' to test selector.

Exit code: 83 (RESOURCE_NOT_FOUND)
Errors go to stderr - stdout remains clean for piping, even on failure

Typo Detection

For commands with limited choices, bdg suggests corrections:
bdg cdp Network.getCokies  # Typo in method name
Error: Method 'getCokies' not found in domain 'Network'

Did you mean:
  Network.getCookies (edit distance: 2)
  Network.setCookies (edit distance: 3)
  Network.getAllCookies (edit distance: 4)

Tip: Use 'bdg cdp Network --list' to see all available methods

Exit code: 81 (INVALID_ARGUMENTS)
Levenshtein distance algorithm finds closest matches within edit distance of 3

Index vs Selector Errors

bdg distinguishes between index-based and selector-based failures:

Selector Error (Element Never Existed)

bdg dom click "#missing-button"
{
  "success": false,
  "error": "Element not found: #missing-button",
  "exitCode": 83,  // RESOURCE_NOT_FOUND
  "suggestion": "Verify selector exists on page. Use 'bdg dom query \"#missing-button\"' to test selector."
}

Index Error (Element Became Stale)

bdg dom query "button"  # Caches nodeIds for indices 0, 1, 2
# ... page navigates ...
bdg dom click 0         # Index 0 nodeId is now stale
{
  "success": false,
  "error": "Element at index 0 not accessible",
  "exitCode": 87,  // STALE_CACHE (not RESOURCE_NOT_FOUND)
  "suggestion": "Re-run query to refresh cache. DOM was modified or page navigated."
}
87 (STALE_CACHE) is recoverable - re-run query and retry. 83 (RESOURCE_NOT_FOUND) is not - selector is wrong.

Validation Errors

bdg validates input before execution and provides specific error messages:
bdg dom scroll --down -50  # Negative scroll value
{
  "success": false,
  "error": "Invalid scroll amount: -50. Must be positive.",
  "exitCode": 81,
  "suggestion": "Use --up 50 to scroll upward, or --down 50 to scroll downward."
}
bdg network har /invalid/path
{
  "success": false,
  "error": "Permission denied: /invalid/path",
  "exitCode": 82,
  "suggestion": "Check file permissions or use '-' to output to stdout."
}

CDP Method Errors

CDP errors are wrapped with context:
bdg cdp Network.setCookie --params '{"name":"test","value":"123","url":"invalid-url"}'
{
  "success": false,
  "error": "CDP error: Invalid URL",
  "exitCode": 81,
  "suggestion": "Ensure 'url' parameter is a valid URL with protocol (http:// or https://).",
  "details": {
    "method": "Network.setCookie",
    "invalidParameter": "url",
    "providedValue": "invalid-url"
  }
}

Timeout Errors

Timeout errors include duration information:
bdg cdp Runtime.evaluate --params '{"expression":"while(true){}"}'
{
  "success": false,
  "error": "CDP operation timed out after 30000ms",
  "exitCode": 102,
  "suggestion": "Operation exceeded timeout. Check for infinite loops or slow operations.",
  "details": {
    "method": "Runtime.evaluate",
    "timeout": 30000
  }
}

Error Handling Best Practices

Exit codes are more reliable than parsing error messages. Use numeric ranges for category detection.
// Good
if (exitCode === 87) {
  refreshCache();
}

// Bad
if (error.includes('stale')) {
  refreshCache();
}
Suggestions include executable commands. Parse and run them directly.
const result = await exec('bdg dom click "#btn"');
if (!result.success && result.suggestion) {
  // Extract command from suggestion
  const suggestedCmd = extractCommand(result.suggestion);
  await exec(suggestedCmd);
}
Software errors (100-109) may be transient. Retry with increasing delays.
async function retryWithBackoff(cmd: string, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const result = await exec(cmd);
    if (result.exitCode === 0) return result;
    
    if (result.exitCode >= 100 && result.exitCode <= 109) {
      await sleep(Math.pow(2, i) * 1000);  // 1s, 2s, 4s
      continue;
    }
    
    // Non-retryable error
    throw new Error(result.error);
  }
}
Internal software errors (110-119) indicate bugs. Report and escalate.
if (exitCode >= 110 && exitCode <= 119) {
  // Report bug, don't retry
  reportBug({
    error: result.error,
    exitCode: result.exitCode,
    command: cmd
  });
  throw new Error('Unrecoverable error');
}
When using --json, parse errors in try-catch to handle malformed output.
try {
  const result = JSON.parse(await exec('bdg dom query "button" --json'));
  if (!result.success) {
    handleError(result);
  }
} catch (e) {
  // JSON parse failed - likely stderr output
  console.error('Non-JSON error:', e);
}

Error Debugging

For unexpected errors, use verbose mode:
bdg dom click "button" --json --verbose
Verbose mode includes additional context in details:
{
  "success": false,
  "error": "Element not found: button",
  "exitCode": 83,
  "suggestion": "Verify selector exists on page.",
  "details": {
    "selector": "button",
    "querySelector": "document.querySelector('button')",
    "documentState": "complete",
    "currentUrl": "https://example.com",
    "timestamp": 1735689600000
  }
}

Next Steps

Discovery Pattern

Learn how agents discover capabilities

Benchmarks

See error handling in real debugging tasks

Troubleshooting

Common issues and solutions

Build docs developers (and LLMs) love