You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
TL;DR — Three separate resolvers decide which token a command uses, and they disagree. resolveToken ignores APIFY_TOKEN, mcp install honors it, the actor entrypoint requires it. On top of that, getLoggedClient() persists whatever token it resolved, so a one-off token overwrites the stored login. Fix: one resolver, one order, and only apify login writes credentials. Two stacked PRs, no data migration.
resolveToken — utils.ts:132, behind all 46 getLoggedClientOrThrow() calls
passed token → stored. No env.
resolveApifyToken — mcp/install.ts:13
--token → APIFY_TOKEN → stored
getApifyTokenFromEnvOrAuthFile — lib/actor.ts:24
APIFY_TOKEN → stored
Same shell, three answers depending on the command. --token exists on 2 of ~50 commands.
Second defect, found in the review of #1293: getLoggedClient() both resolves and persists. Once the resolver returns an env token, setToken() writes it over the stored login and rewrites username/id. The stored account is replaced by a transient env var, and it survives unset.
Decision
--token → APIFY_TOKEN → stored
This is not a new rule. mcp install and the actor entrypoint already work this way; only resolveToken does not. It also needs no special case for the actor CLI: inside a platform run there is no stored login, so APIFY_TOKEN wins on its own.
Scope
One resolver. Delete getApifyTokenFromEnvOrAuthFile (lib/actor.ts:24, used by actor charge) and resolveApifyToken (mcp/install.ts:13).
loginWithToken(token) — authenticates and saves. Only apify login calls it.
--token becomes a global flag through baseOptions in _buildParseArgsOption, next to --help and --user-agent. On login it keeps today's meaning, save the token. Everywhere else it is one-off and stores nothing.
apify login ignores APIFY_TOKEN. Logging in is explicit.
apify auth token prints the token that would be used, not getLocalUserInfo().token. It only looks right today because of the overwrite bug.
apify run passes the resolved token to the child and stops overwriting an inherited APIFY_TOKEN (run.ts:331).
A rejected token names its source: "APIFY_TOKEN is set but was rejected" is not the same message as "not logged in".
Supersedes. First attempt. Correct read-side precedence, blocked because getLoggedClient persisted the env token over the stored login. Its tests are worth lifting from claude/apify-token-permissions-bug-15c25d.
Related, not closed. Touches the same line (run.ts:331), but the hang is the child SDK blocking on a terminal-status POST. The fix may belong in the SDK.
Note
TL;DR — Three separate resolvers decide which token a command uses, and they disagree.
resolveTokenignoresAPIFY_TOKEN,mcp installhonors it, theactorentrypoint requires it. On top of that,getLoggedClient()persists whatever token it resolved, so a one-off token overwrites the stored login. Fix: one resolver, one order, and onlyapify loginwrites credentials. Two stacked PRs, no data migration.Part of #1383 (Stage-1).
Problem
resolveToken—utils.ts:132, behind all 46getLoggedClientOrThrow()callsresolveApifyToken—mcp/install.ts:13--token→APIFY_TOKEN→ storedgetApifyTokenFromEnvOrAuthFile—lib/actor.ts:24APIFY_TOKEN→ storedSame shell, three answers depending on the command.
--tokenexists on 2 of ~50 commands.Second defect, found in the review of #1293:
getLoggedClient()both resolves and persists. Once the resolver returns an env token,setToken()writes it over the stored login and rewritesusername/id. The stored account is replaced by a transient env var, and it survivesunset.Decision
This is not a new rule.
mcp installand theactorentrypoint already work this way; onlyresolveTokendoes not. It also needs no special case for theactorCLI: inside a platform run there is no stored login, soAPIFY_TOKENwins on its own.Scope
getApifyTokenFromEnvOrAuthFile(lib/actor.ts:24, used byactor charge) andresolveApifyToken(mcp/install.ts:13).resolveAuth()— reads only.--token→APIFY_TOKEN→ stored.loginWithToken(token)— authenticates and saves. Onlyapify logincalls it.--tokenbecomes a global flag throughbaseOptionsin_buildParseArgsOption, next to--helpand--user-agent. Onloginit keeps today's meaning, save the token. Everywhere else it is one-off and stores nothing.apify loginignoresAPIFY_TOKEN. Logging in is explicit.apify auth tokenprints the token that would be used, notgetLocalUserInfo().token. It only looks right today because of the overwrite bug.apify runpasses the resolved token to the child and stops overwriting an inheritedAPIFY_TOKEN(run.ts:331).Commit order
loginWithTokenadded, onlyloginpersists.--token,runchild env.Never the reverse. Precedence without the guard is the #1293 data-loss bug.
Open
--tokenon every command, or only ones that authenticate? Suggest every command — the resolver is global and exceptions are hard to maintain.username.push,calland others need it. Suggest a lazy in-memory lookup, only when the command needs it.apify infonames the source instead.Supersedes and related
APIFY_TOKENto work as a parameter or env var.--tokenhere is the actual fix.getLoggedClientpersisted the env token over the stored login. Its tests are worth lifting fromclaude/apify-token-permissions-bug-15c25d.run.ts:331), but the hang is the child SDK blocking on a terminal-status POST. The fix may belong in the SDK.APIFY_TOKENin their docs. Tell them the outcome — support stays, precedence is now defined.Notes
resolveTokenhappy-path pin first.🤖 Generated with Claude Code