pbakaus/impeccable · error

Reply failed: Unauthorized

Error message

Reply failed: Unauthorized

What it means

A 401 response on the reply POST is mapped to this hardcoded message. The live server rejected the authentication token that live-poll sent, so the reply was not accepted. Matching the JS implementation, the command prints `Reply failed: Unauthorized` and exits 1.

Source

Thrown at crates/live/src/live_poll.rs:731

            Ok(Some(r)) => r,
            Ok(None) => return 0,
            Err(msg) => {
                io.err(&format!("{}\n", msg));
                return 1;
            }
        };
        return match post_reply(&base, &token, &reply) {
            Ok(()) => 0,
            Err(PollError::ConnRefused) => {
                io.err(&format!(
                    "Live server not running. Start one with: {}\n",
                    script_cmd(&env, &cwd, "live")
                ));
                1
            }
            Err(PollError::Auth) => {
                // JS: a 401 on the reply POST is a non-ok response -> "Reply failed: <body.error>"
                io.err("Reply failed: Unauthorized\n");
                1
            }
            Err(PollError::AckTimeout(m)) | Err(PollError::Other(m)) => {
                io.err(&format!("Reply failed: {}\n", m));
                1
            }
        };
    }

    let stream_mode = argv.iter().any(|a| a == "--stream");
    let types_arg = argv
        .iter()
        .find(|a| a.starts_with("--types="))
        .map(|a| a["--types=".len()..].to_string());
    let types = normalize_poll_types(types_arg.as_deref());
    let ack_timeout_ms = arg_value_int(&argv, "--ack-timeout=", 600_000);

    if stream_mode {

View on GitHub (pinned to 2bc2879276)

Solutions

  1. Stop and restart the live server so the info file's token matches the running process, then retry the reply.
  2. Delete the stale server info file and start a fresh `live` session.
  3. Ensure only one live server session exists for the workspace so poll reads the correct token.

Example fix

// before
$ impeccable live-poll --reply --reply-text hi
Reply failed: Unauthorized
// after
$ <self_cmd> live-server stop
$ ./scripts/impeccable live &
$ impeccable live-poll --reply --reply-text hi
Defensive patterns

Strategy: fallback

Validate before calling

// shell: if the info file predates the running server process, restart to refresh the token
pid=$(jq -r .pid .impeccable/live-server.json 2>/dev/null)
kill -0 "$pid" 2>/dev/null || { <self_cmd> live-server stop; ./scripts/impeccable live; }

Try / catch

// on Unauthorized, restart the server and re-read the token before retrying
try {
  postReply(text);
} catch (e) {
  if (/Unauthorized/.test(String(e.stderr))) {
    execSync('<self_cmd> live-server stop && ./scripts/impeccable live');
    postReply(text); // retry with fresh token from the new info file
  } else throw e;
}

Prevention

When it happens

Trigger: `impeccable live-poll --reply` where `post_reply` returns `PollError::Auth` — the token read from the server info file does not match what the live server expects (401 from the endpoint).

Common situations: The live server was restarted and generated a new token while an old info file was reused; two live sessions in the same workspace and polling the wrong one; manually editing or copying session files between directories.

Understand the failure class

Related errors


AI-assisted analysis of pbakaus/impeccable@2bc2879276 (2026-09-08). Data as JSON: /api/errors/825233c42d867aa8. Report an issue: GitHub.