{"record":{"id":"7fcf74066083bd56","repo":"mastra-ai/mastra","slug":"github-token-refresh-requires-an-active-factory-sa","errorCode":null,"errorMessage":"GitHub token refresh requires an active Factory sandbox workspace.","messagePattern":"GitHub token refresh requires an active Factory sandbox workspace\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/integrations/github/token-refresh.ts","lineNumber":29,"sourceCode":"  requestContext.set(GITHUB_TOKEN_INJECTOR_CONTEXT_KEY, injector);\n}\n\n/** Record which PAT kind the active sandbox was provisioned with, so token\n * refresh re-injects the same credential (review-board sandboxes keep the\n * reviewer token instead of being clobbered with the worker token). */\nexport function registerGithubPatKind(requestContext: RequestContext, kind: GithubPatKind): void {\n  requestContext.set(GITHUB_PAT_KIND_CONTEXT_KEY, kind);\n}\n\nexport function getRegisteredGithubPatKind(requestContext: RequestContext): GithubPatKind {\n  const kind = requestContext.get(GITHUB_PAT_KIND_CONTEXT_KEY);\n  return kind === 'reviewer' ? 'reviewer' : 'default';\n}\n\nexport function injectGithubToken(requestContext: RequestContext, token: string): void {\n  const injector = requestContext.get(GITHUB_TOKEN_INJECTOR_CONTEXT_KEY) as GithubTokenInjector | undefined;\n  if (!injector) {\n    throw new Error('GitHub token refresh requires an active Factory sandbox workspace.');\n  }\n  injector(token);\n}\n","sourceCodeStart":11,"sourceCodeEnd":33,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/integrations/github/token-refresh.ts#L11-L33","documentation":"injectGithubToken looks up a GithubTokenInjector registered in the RequestContext under GITHUB_TOKEN_INJECTOR_CONTEXT_KEY. That injector is only registered when the request runs inside an active Factory sandbox workspace, since token injection mutates live sandbox credentials. Running outside a sandbox (local dev, plain server context, tests) leaves the injector absent, so the code throws instead of silently dropping the token.","triggerScenarios":"Calling injectGithubToken (typically from refreshGithubToken, which is invoked by the GitHub subscription tools) with a RequestContext that has no GithubTokenInjector bound — i.e. no Factory sandbox workspace is active for that request context.","commonSituations":"Running GitHub subscription tooling locally outside the Factory sandbox; tests that build a bare new RequestContext() without sandbox wiring; a refactor renamed or removed the sandbox bootstrap that registers the injector; the token refresh runs after the sandbox was torn down.","solutions":["Run the token refresh inside an active Factory sandbox workspace so the injector is registered in the RequestContext","Ensure the sandbox bootstrap (workspace provisioning) executes before any GitHub subscription tool can call refreshGithubToken","In tests/local dev, register a stub GithubTokenInjector in the RequestContext under GITHUB_TOKEN_INJECTOR_CONTEXT_KEY","Guard the call site: skip refreshGithubToken when the injector is absent and log instead of throwing"],"exampleFix":"// before\nrequestContext.set('github-token-injector', undefined);\nawait refreshGithubToken(requestContext, github); // throws\n// after\nrequestContext.set(GITHUB_TOKEN_INJECTOR_CONTEXT_KEY, (token: string) => {\n  sandboxCredentials.setGithubToken(token);\n});\nawait refreshGithubToken(requestContext, github);","handlingStrategy":"type-guard","validationCode":"const injector = requestContext.get(GITHUB_TOKEN_INJECTOR_CONTEXT_KEY) as GithubTokenInjector | undefined;\nif (typeof injector !== 'function') {\n  throw new Error('Token refresh skipped: no Factory sandbox workspace active.');\n}","typeGuard":"function hasGithubTokenInjector(requestContext: RequestContext): boolean {\n  return typeof requestContext.get(GITHUB_TOKEN_INJECTOR_CONTEXT_KEY) === 'function';\n}","tryCatchPattern":"try {\n  await injectGithubToken(requestContext, token);\n} catch (err) {\n  if ((err as Error).message.includes('active Factory sandbox workspace')) {\n    logger.warn('Token injection skipped outside sandbox workspace');\n    return;\n  }\n  throw err;\n}","preventionTips":["Ensure sandbox workspace provisioning runs before any GitHub tooling in the request pipeline","Register a no-op or stub injector in local/test RequestContexts","Never tear down the sandbox before pending token refreshes complete","Add an integration test asserting the injector key is bound in production request wiring"],"tags":["github","sandbox","request-context"],"backgroundTag":"missing-runtime-context","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}