mastra-ai/mastra · critical
Credential storage is not available
Error message
Credential storage is not available
What it means
persistOAuthCredential stores OAuth tokens either in the tenant in-memory store or, as a fallback, in a configured authStorage. When neither exists (authStorage is null) the credential would be silently lost, so the function throws instead. It's a configuration error: the factory was assembled without credential storage.
Source
Thrown at mastracode/factory/src/routes/oauth.ts:231
}: {
ctx: CredentialContext;
provider: string;
scope: LoginCredentialScope | undefined;
credentials: OAuthCredentials;
authStorage: AuthStorage | undefined;
onCredentialsChanged: (tenant: { orgId: string; userId?: string }) => void;
}): Promise<void> {
const authProviderId = getAuthProviderId(provider);
if (ctx.mode === 'tenant') {
const tenant = { orgId: ctx.orgId, ...(scope === 'org' ? {} : { userId: ctx.userId }) };
await ctx.storage.setCredential(tenant, authProviderId, {
type: 'oauth',
...credentials,
});
onCredentialsChanged(tenant);
return;
}
if (!authStorage) throw new Error('Credential storage is not available');
authStorage.set(authProviderId, { type: 'oauth', ...credentials });
}
async function readJsonBody(c: Context): Promise<Record<string, unknown>> {
try {
const body = (await c.req.json()) as unknown;
return body && typeof body === 'object' ? (body as Record<string, unknown>) : {};
} catch {
return {};
}
}
export interface OAuthRoutesDeps extends RouteDependencies {
/** File-backed credential store; used in local (no-auth) mode. */
authStorage?: AuthStorage;
/** Tenant credential domain handle; absent in local (no-DB) mode. */
modelCredentials?: ModelCredentialsStorage;
/** Notifies the host after tenant credentials change so caches can be dropped. */View on GitHub (pinned to 75dd419e61)
Solutions
- Configure an authStorage implementation when assembling the factory routes so OAuth credentials can be persisted.
- Verify the factory/bootstrap code actually passes authStorage into the routes options (it may be conditionally omitted).
- If persistence is intentionally unsupported in your environment, pre-handle credentials via the in-memory tenant path or disable OAuth routes.
- In tests, provide a fake authStorage implementing get/set to satisfy the flow.
Example fix
// before
assembleFactoryApiRoutes({ /* no authStorage */ });
// after
assembleFactoryApiRoutes({
authStorage: createAuthStorage({ driver: 'db', url: process.env.DATABASE_URL }),
}); Defensive patterns
Strategy: validation
Validate before calling
function assertCredentialStorageConfigured(opts: { authStorage?: { set(id: string, v: unknown): void } | null }) {
if (!opts.authStorage) throw new Error('authStorage must be configured for OAuth routes');
} Type guard
function hasAuthStorage(o: unknown): o is { authStorage: { set: (id: string, v: unknown) => void } } {
return typeof o === 'object' && o !== null && 'authStorage' in o && (o as any).authStorage != null;
} Try / catch
try {
await completeOAuthFlow(...);
} catch (e) {
if (e instanceof Error && e.message === 'Credential storage is not available') {
logger.error('OAuth credential dropped: configure authStorage in factory options');
return Response.json({ error: 'server misconfiguration: credential storage missing' }, { status: 500 });
}
throw e;
} Prevention
- Always wire authStorage when assembling factory routes in production.
- Add a startup check that fails fast if OAuth routes are enabled without authStorage.
- Use the same storage adapter across environments so staging/prod parity holds.
- In tests, provide an in-memory authStorage stub implementing set/get.
When it happens
Trigger: Completing an OAuth flow (callback/token exchange route) when the factory was built without an authStorage implementation and the credential isn't handled by the in-memory tenant path.
Common situations: Deployments where persistent credential storage wasn't wired in the factory options (e.g. serverless or ephemeral environments with no storage adapter configured); forgetting to pass authStorage when calling assembleFactoryApiRoutes/routes; tests hitting OAuth routes with a stubbed factory config.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Factory source control storage is unavailable
- DURABLE_AGENT_LIST_ACTIVE_RUNS_NO_STORAGE
- Memory requires a storage provider to function. Add a storag
- SCHEDULES_NO_SCHEDULES_STORAGE
- AcpAgent does not support resuming suspended generate calls
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/7d7750bf54416df0.
Report an issue: GitHub.