mastra-ai/mastra · error
GitHub token refresh no longer matches the active Factory wo
Error message
GitHub token refresh no longer matches the active Factory workspace role.
What it means
When a GitHub token is registered for a Factory workspace, the injector closure is bound to both the registration object and a generation counter. If the injector later fires but the registration was replaced (a new generation was registered) or removed, the error is thrown to prevent injecting a token from a stale role into the current workspace context.
Source
Thrown at mastracode/factory/src/workspace.ts:435
};
const resolveGithubPatKind = async (fallback: GithubPatKind): Promise<GithubPatKind> => {
if (!workItems) return 'default';
try {
const address = getFactorySessionAddress(requestContext);
const runBinding = address ? await workItems.findRunBindingBySession(address) : null;
return runBinding?.role === 'review' && runBinding.status === 'active' && runBinding.orgId === session.orgId
? 'reviewer'
: 'default';
} catch {
// Preserve the installed role when binding storage is temporarily unavailable.
return fallback;
}
};
const registerGithubTokenContext = (registered: GithubTokenRegistration): void => {
const generation = registered.generation;
registerGithubTokenInjector(requestContext, token => {
if (githubTokenInjectors.get(workspaceId) !== registered || registered.generation !== generation) {
throw new Error('GitHub token refresh no longer matches the active Factory workspace role.');
}
registered.inject(token);
});
registerGithubPatKind(requestContext, registered.patKind);
};
const reconcileGithubToken = async (): Promise<void> => {
const previous = githubTokenReconciliations.get(workspaceId) ?? Promise.resolve();
const reconciliation = previous
.catch(() => {})
.then(async () => {
const registered = githubTokenInjectors.get(workspaceId);
if (!registered) return;
const previousPatKind = registered.patKind;
const patKind = await resolveGithubPatKind(previousPatKind);
if (githubTokenInjectors.get(workspaceId) !== registered) return;
if (patKind !== previousPatKind) {View on GitHub (pinned to 75dd419e61)
Solutions
- Retry the operation — reconciliation will re-register a fresh token context and the next refresh will match
- Check for concurrent setup/reconciliation paths racing on the same workspaceId and serialize them
- Restart or re-materialize the workspace so token registration and role are consistent
- Upgrade: if this fires repeatedly without role changes, it indicates a generation-tracking bug — capture diagnostics
Defensive patterns
Strategy: retry
Validate before calling
// before relying on the injector, confirm the current registration is still active
const current = githubTokenInjectors.get(workspaceId);
if (current !== registered || registered.generation !== generation) {
await reRegisterGithubTokenContext(); // refresh instead of injecting stale token
} Try / catch
try {
await runWithGithubToken(requestContext, token => registered.inject(token));
} catch (e) {
if (e instanceof Error && e.message.includes('no longer matches the active Factory workspace role')) {
await reconcileGithubToken(); // retry with fresh registration
} else throw e;
} Prevention
- Serialize workspace reconciliation per workspaceId to avoid generation races
- Avoid holding token injector references across role switches
- Re-read the registration after any role/impersonation change
- Log generation changes to diagnose recurring staleness
When it happens
Trigger: A token refresh callback runs after `registerGithubTokenInjector` was superseded: `githubTokenInjectors.get(workspaceId)` no longer equals `registered`, or `registered.generation` differs from the captured `generation`. Raised via registerGithubTokenContext during setupHook or reconciliation.
Common situations: Concurrent workspace reconciliation re-registering credentials while an old refresh is in flight; workspace role switched (e.g., different PAT kind or user impersonation) mid-session; race between session teardown and a pending token refresh.
Related errors
- Repository access did not include a bearer token for the Fac
- Factory workspace GitHub credential registration is no longe
- GitHub capabilities require a GitHub connection.
- Factory kickoff was queued onto an ending run and never reac
- Factory session ${session.sessionId} was retired during work
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/1321c09909a07f36.
Report an issue: GitHub.