## TL;DR

The access token expired mid-run and every subsequent API call fails. Refresh the token (or re-authenticate), then resume from the run's checkpoint with the new token. Long runs must treat token refresh as routine, not as an error.

## Error

```text
Auth error: 401 Unauthorized on dedupe API calls; token expired mid-run.
```

## Steps

1. Detect 401s distinctly from other errors. Expected: the run knows this is auth, not data.
2. Refresh the access token using the stored refresh credential (never ask a human mid-run). Expected: a fresh token.
3. Resume from the checkpoint with the new token; do not restart. Expected: the run continues.
4. Proactively refresh before expiry on long runs (refresh at 75 percent of token lifetime). Expected: expiry never interrupts.
5. Alert if refresh itself fails; that needs human attention (revoked or rotated credentials). Expected: the right escalation.

## When to use

- Long runs fail with 401s partway.
- An agent holds one token for a multi-hour job.
- After token lifetime policies change.

## When not to use

- Invalid credentials from the start (fix the auth setup).
- 403s (permissions, not expiry).

## Tool compatibility

- OAuth refresh flows; HubSpot and Salesforce token lifetimes.
- Agent checkpoint and resume.

## Variant phrasings

### token expired mid-run

Refresh and resume from checkpoint.

### 401s partway through dedupe

Same recovery; make refresh proactive.

## Why it happens

Access tokens have fixed lifetimes (often 30 to 60 minutes for some flows, longer for others). Runs longer than the lifetime outlive their credentials.

## Edge cases

- Refresh credentials can expire too; handle with a full re-auth path and an alert.
- Clock skew can make tokens appear expired early; keep host clocks synced.
- Concurrent workers should share one refreshed token, not each refresh independently.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_DzrsRSQhn_B3LTXBcH4RWg
