Skip to content

fix(upload): read the persisted login token again before each upload - #567

Closed
SuperMuel wants to merge 2 commits into
mainfrom
cod-3768-wizard-codspeed-run-uploads-fail-with-401-when-the-run
Closed

SuperMuel wants to merge 2 commits into
mainfrom
cod-3768-wizard-codspeed-run-uploads-fail-with-401-when-the-run

Conversation

@SuperMuel

@SuperMuel SuperMuel commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

A run starts with token 1. Token 1 expires at 15:28. The upload at 16:03 fails with 401.

Problem

codspeed run reads the token saved by codspeed auth login once, at start. It uploads with that same token at the end.

If the token expires during the run, the upload fails with 401 Invalid token, and all the results are lost. Running codspeed auth login again during the run does not help: the running CLI never reads the new token.

For example, a setup that saves a new 1-hour token before the old one expires still loses a 53-minute run this way.

Fix

Read the saved token again right before each upload. This is what the CLI already does for OIDC tokens in CI.

  • Only the token saved by codspeed auth login is read again. A token from --token, CODSPEED_TOKEN, --oauth-token or CODSPEED_OAUTH_TOKEN can't change during a run, so it stays as is.
  • The token is still checked at start, so a missing or invalid token still stops the run before the benchmarks.
  • If the saved token can't be read again, the run keeps the token it started with.

Proof

A 30 s walltime run, with the saved token changed 12 s into the run:

CLI Token change during the run Upload
this branch new valid token OK, with the new token
this branch invalid token 401, so the upload really uses the new token
5.4.0 invalid token OK, with the start token (old behavior)
this branch invalid token at start stops before the benchmarks

The unit tests in api_client.rs cover the same cases.

Refs COD-3768

@SuperMuel
SuperMuel requested a review from fargito October 6, 2026 09:40
@greptile-apps

greptile-apps Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Critical risk] Changes how authentication tokens are loaded before uploads.

The PR should address concurrent login writes before merging, because an upload can still use an expired token and lose results.

Fix All in Claude CodeFindings

  1. P1 Expired token survives concurrent login ▶
Fix with agent prompt
### Issue 1
src/api_client.rs:136-139
If `codspeed auth login` is writing a refreshed token when the upload rereads the config, the read can encounter a partial file. This branch then keeps the token from the start of the run. If that token has expired, the upload fails and the run’s results are lost-the failure this change aims to prevent. The login path uses `fs::write`, so the refresh needs an atomic read/write boundary or a retry before falling back.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The PR distinguishes persisted login tokens from explicit tokens and rereads the selected profile before each upload, while retaining the initial token when rereading fails. It also adds token-reload tests and confines the legacy-config test’s environment override.

Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Start run with persisted token] --> B[Run benchmarks]
  B --> C[Before each upload: reread selected profile]
  C -->|New token| D[Replace client authentication]
  C -->|Read fails or token absent| E[Keep in-memory token]
  D --> F[Upload]
  E --> F
Loading

Reviews (1) · Last reviewed commit: "fix(upload): read the persisted login to..."

Comment thread src/api_client.rs
Comment on lines +136 to +139
Err(err) => warn!(
"Failed to read the token of profile `{}` again, keeping the one this run started with: {err}",
profile.profile_name
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Expired token survives concurrent login

If codspeed auth login is writing a refreshed token when the upload rereads the config, the read can encounter a partial file. This branch then keeps the token from the start of the run. If that token has expired, the upload fails and the run’s results are lost—the failure this change aims to prevent. The login path uses fs::write, so the refresh needs an atomic read/write boundary or a retry before falling back.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/api_client.rs
Line: 136-139

Comment:
**Expired token survives concurrent login**

If `codspeed auth login` is writing a refreshed token when the upload rereads the config, the read can encounter a partial file. This branch then keeps the token from the start of the run. If that token has expired, the upload fails and the run’s results are lost—the failure this change aims to prevent. The login path uses `fs::write`, so the refresh needs an atomic read/write boundary or a retry before falling back.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid, but very unlikely (a tiny file rewritten about once an hour), and in that case the run keeps its start token, which is the current behavior, so I'd leave an atomic write in auth login for a follow-up.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That’s fair. The race window is small, and falling back to the run-start token preserves the existing behavior rather than introducing a regression in this PR. I’ll consider the partial-read risk deferred to a follow-up that makes the auth login profile write atomic.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

@codspeed

codspeed Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

✅ 31 untouched benchmarks
⏩ 6 skipped benchmarks1


Comparing cod-3768-wizard-codspeed-run-uploads-fail-with-401-when-the-run (82b94ce) with main (bcad8db)

Open in CodSpeed

Footnotes

  1. 6 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

`codspeed run` read the token persisted by `codspeed auth login` once,
at start, and uploaded with it. A run that outlived that token (the
Wizard refreshes its one-hour tokens by running `codspeed auth login`
again while the benchmarks run) uploaded with the expired one and
failed with `401 Unauthorized -> Reason: Invalid token`, losing the
results of the whole run.

Read the profile token again right before each upload, the same way an
OIDC token is minted again. Tokens given through `--token` or
`--oauth-token` cannot change while the run goes, so they are kept as
they are. The token is still read at start, so a missing or invalid
token fails the command before the benchmarks run.

The legacy-config test now isolates `XDG_CONFIG_HOME` with `temp_env`
instead of setting it for the whole process, so it does not race with
the new tests.

Refs COD-3768

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@SuperMuel
SuperMuel force-pushed the cod-3768-wizard-codspeed-run-uploads-fail-with-401-when-the-run branch from acac8f1 to 6be3b53 Compare October 6, 2026 10:06
Comment thread src/api_client.rs Outdated
Comment on lines +35 to +44
/// A token obtained through `codspeed auth login` and passed through
/// `--oauth-token` / `CODSPEED_OAUTH_TOKEN`.
CliLogin(String),
/// The token `codspeed auth login` persisted for the selected profile. Read
/// again before every upload, because a login that ran during the
/// benchmarks may have stored a newer token.
PersistedCliLogin {
token: String,
profile: ProfileLocation,
},

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to add a new authentication method? We can keep the same method and simply re-resolve it before upload right? Isn't it what we talked about?

@SuperMuel SuperMuel Oct 6, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This keeps the profile selected at the start of the run, to avoid this case:

  1. codspeed profile set A
  2. codspeed run starts and reads the token of profile A
  3. codspeed profile set B
  4. codspeed run finishes, and the upload reads the token of profile B

It's probably rare, but possible.

@SuperMuel SuperMuel Oct 6, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this edge case is too unlikely to be worth handling?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think it a bit far-fetched. What you are telling me here is that the existing CliLogin method does not read the profile file? If it does, then maybe the ProfileLocation should be added to CliLogin instead of creating a duplicated logic

`CliLogin` already holds the token persisted by `codspeed auth login`.
Give it an optional `ProfileLocation` instead of adding a separate
variant: `Some` when the token was read from a profile, so it is read
again before each upload, and `None` when it came from `--oauth-token`
or `CODSPEED_OAUTH_TOKEN`. No behavior change.

Refs COD-3768

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@SuperMuel

Copy link
Copy Markdown
Contributor Author

Closing: instead of reading the token again from disk, the CLI will get a refresh mechanism (COD-3776).

@SuperMuel SuperMuel closed this Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants