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

  1. Retry the operation — reconciliation will re-register a fresh token context and the next refresh will match
  2. Check for concurrent setup/reconciliation paths racing on the same workspaceId and serialize them
  3. Restart or re-materialize the workspace so token registration and role are consistent
  4. 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

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/1321c09909a07f36. Report an issue: GitHub.