## TL;DR

Salesforce sessions expire (often after 2 hours), and a long batch job outlives its session. Catch the session-expired error, obtain a fresh session, and retry the failed batch from its start. Never let a multi-hour job run on a single login without refresh logic.

## Error

```text
[ {
  "message" : "Session expired or invalid",
  "errorCode" : "INVALID_SESSION_ID"
} ]
```

## Steps

1. Detect INVALID_SESSION_ID distinctly from other errors in the batch loop. Expected: the loop knows this is recoverable.
2. Re-authenticate (refresh the OAuth token or log in again) to get a fresh session id. Expected: a valid session.
3. Retry the failed batch with the new session, from the batch start. Expected: the batch completes.
4. For OAuth, prefer the refresh flow over full re-login; it is faster and does not need the user. Expected: seamless recovery.
5. Proactively refresh the session before long batches, or split batches to fit within the session lifetime. Expected: expiry never interrupts.

## When to use

- Batch jobs fail with INVALID_SESSION_ID after running a while.
- An agent's multi-hour load dies at the same elapsed time each run.
- After org session timeout settings change.

## When not to use

- INVALID_LOGIN at startup (credentials wrong from the beginning).
- invalid_grant on OAuth (different flow problem).

## Tool compatibility

- Salesforce SOAP and REST sessions; OAuth refresh flow.
- Any long-running batch client.

## Variant phrasings

### Session expired or invalid

Refresh and retry the batch.

### INVALID_SESSION_ID mid-run

Same recovery; make it automatic.

## Why it happens

Sessions have a fixed lifetime regardless of activity. Jobs longer than the timeout outlive their credentials, and the API rejects every subsequent call.

## Edge cases

- Refresh tokens can also expire; handle that with a full re-auth path.
- Concurrent workers sharing one session can invalidate each other; give each worker its own session.
- Retry the batch from its start; partial batches may have partially applied.

## Provenance

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