Kuberwastaken/claurst · error

Remote Control requires a session token. Set…

Error message

Remote Control requires a session token.
Set CLAURST_BRIDGE_TOKEN=<your-token> to enable.
Get a token from https://claude.ai (Settings → Remote Control).
Note: Remote Control is only available with claude.ai subscriptions.

What it means

This is the user-facing startup error for the Remote Control bridge when no session token can be resolved. The start path tries (in order): an explicit token override, the CLAURST_BRIDGE_TOKEN env var, and the CLAUDE_BRIDGE_OAUTH_TOKEN env var; if all are missing or empty, it fails with instructions on how to enable Remote Control. It also documents that Remote Control requires a claude.ai subscription.

Solutions

  1. Get a token from claude.ai (Settings → Remote Control) and run `export CLAURST_BRIDGE_TOKEN=<your-token>` before starting.
  2. Alternatively set `CLAUDE_BRIDGE_OAUTH_TOKEN` if you obtained an OAuth bridge token.
  3. Check the variable is non-empty: `echo "${CLAURST_BRIDGE_TOKEN:?not set}"`.
  4. If you have no subscription, Remote Control is unavailable — use the app without it.

Example fix

// before
$ ./claurst  # Remote Control requires a session token...
// after
$ export CLAURST_BRIDGE_TOKEN=eyJhbGci...
$ ./claurst
Defensive patterns

Strategy: validation

Validate before calling

// Shell preflight before launching
[ -n "$CLAURST_BRIDGE_TOKEN" ] || [ -n "$CLAUDE_BRIDGE_OAUTH_TOKEN" ] || { echo "Set CLAURST_BRIDGE_TOKEN (claude.ai Settings -> Remote Control)"; exit 1; }

Try / catch

// Rust caller: surface the actionable message instead of a raw trace
if let Err(e) = start_bridge(token_override).await {
    eprintln!("{e:#}"); // prints the multi-line setup instructions
    std::process::exit(2);
}

Prevention

When it happens

Trigger: Starting the bridge (the function at bridge/src/lib.rs:938) with no `token_override`, no `CLAURST_BRIDGE_TOKEN`, and no `CLAUDE_BRIDGE_OAUTH_TOKEN` env var — or all present but empty strings (filtered by `.filter(|t| !t.is_empty())`).

Common situations: User runs Remote Control on a fresh machine without exporting the token; token set to empty string in shell config; user has an API-key-only (non-subscription) account where no bridge token exists; token env var name misspelled.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10). Data as JSON: /api/errors/1c5a09b82dbc072e. Report an issue: GitHub.

Appendix: source

Thrown at src-rust/crates/bridge/src/lib.rs:938

///
/// ```rust,no_run
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
/// match claurst_bridge::start_bridge_session(None).await {
///     Ok(info) => println!("Session URL: {}", info.session_url),
///     Err(e) => eprintln!("Could not start bridge: {e}"),
/// }
/// # });
/// ```
pub async fn start_bridge_session(
    token_override: Option<String>,
) -> anyhow::Result<BridgeSessionInfo> {
    // Resolve auth token.
    let token = token_override
        .or_else(|| std::env::var("CLAURST_BRIDGE_TOKEN").ok())
        .or_else(|| std::env::var("CLAUDE_BRIDGE_OAUTH_TOKEN").ok())
        .filter(|t| !t.is_empty())
        .ok_or_else(|| {
            anyhow::anyhow!(
                "Remote Control requires a session token.\n\
                 Set CLAURST_BRIDGE_TOKEN=<your-token> to enable.\n\
                 Get a token from https://claude.ai (Settings → Remote Control).\n\
                 Note: Remote Control is only available with claude.ai subscriptions."
            )
        })?;

    // Resolve server base URL.
    let server_url = std::env::var("CLAURST_BRIDGE_URL")
        .or_else(|_| std::env::var("CLAUDE_BRIDGE_BASE_URL"))
        .unwrap_or_else(|_| "https://claude.ai".to_string());

    let session_id = uuid::Uuid::new_v4().to_string();

    let hostname = {
        hostname::get()
            .map(|h| h.to_string_lossy().into_owned())
            .unwrap_or_else(|_| "unknown".to_string())

View on GitHub (pinned to b0637c97ec)