mastra-ai/mastra · error
Google Directory groups.list failed (${response.status}): ${
Error message
Google Directory groups.list failed (${response.status}): ${await response.text()} What it means
Thrown by MastraRBACGoogle.fetchRolesFromGoogle when the Admin SDK Directory API groups.list call (https://admin.googleapis.com/admin/directory/v1/groups) returns a non-OK status. The HTTP status and raw response body are embedded in the message. It means the bearer token was rejected or the Directory API refused the query (permissions, domain, userKey problems).
Source
Thrown at auth/google/src/rbac-provider.ts:158
do {
const url = new URL(DIRECTORY_GROUPS_URL);
url.searchParams.set('userKey', userKey);
url.searchParams.set('maxResults', '200');
if (pageToken) {
url.searchParams.set('pageToken', pageToken);
}
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${token}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(DEFAULT_FETCH_TIMEOUT_MS),
});
if (!response.ok) {
throw new Error(`Google Directory groups.list failed (${response.status}): ${await response.text()}`);
}
const json = (await response.json()) as GroupsListResponse;
for (const group of json.groups ?? []) {
const mappedRoles = this.options.mapGroupToRoles?.(group) ?? [group.email];
for (const role of mappedRoles) {
if (role) roles.add(role);
}
}
pageToken = json.nextPageToken;
} while (pageToken);
return Array.from(roles);
}
private async getToken(): Promise<string> {
if (this.options.getAccessToken) {
return this.options.getAccessToken();View on GitHub (pinned to 75dd419e61)
Solutions
- Read the HTTP status in the message: 401 => refresh/fix the token; 403 => fix delegation/scopes; 404/400 => check userKey.
- For service accounts, enable domain-wide delegation in Workspace Admin and set subject to an admin email with group read rights.
- Ensure the token scope includes https://www.googleapis.com/auth/admin.directory.group.readonly and the Admin SDK API is enabled in the Google Cloud project.
- Verify the user's email (or getUserKey result) belongs to the Workspace domain and is a valid userKey.
- Confirm the Admin SDK Directory API is enabled for the project in Google Cloud Console.
- Handle transient 5xx with a retry; fetchRolesFromGoogle errors are logged and rethrown after cache eviction.
Example fix
// before (no subject => service account has no delegated identity)
const rbac = new MastraRBACGoogle({ serviceAccount: { clientEmail, privateKey } });
// after
const rbac = new MastraRBACGoogle({
serviceAccount: {
clientEmail,
privateKey,
subject: 'admin@mycompany.com', // domain-wide delegation target
scopes: ['https://www.googleapis.com/auth/admin.directory.group.readonly'],
},
roleMapping: { _default: [] },
}); Defensive patterns
Strategy: retry
Validate before calling
// before calling getRoles, confirm a usable Directory token exists and the user key is plausible
if (!user.email || !user.email.includes('@')) return []; // skip Directory lookup for invalid keys
// ensure API access once at startup:
// admin.googleapis.com Admin SDK enabled + token scope includes admin.directory.group.readonly Type guard
function isDirectoryApiError(err: unknown): err is Error & { message: string } {
return err instanceof Error && err.message.startsWith('Google Directory groups.list failed (');
}
function directoryStatus(err: Error & { message: string }): number | null {
const m = /groups\.list failed \((\d{3})\)/.exec(err.message);
return m ? Number(m[1]) : null;
} Try / catch
try {
const roles = await rbac.getRoles(user);
} catch (err) {
if (isDirectoryApiError(err)) {
const status = directoryStatus(err);
if (status === 429 || (status && status >= 500)) {
await retryWithBackoff(() => rbac.getRoles(user)); // transient — safe to retry
} else {
// 401/403: fix token/delegation/scopes; 404/400: bad userKey — do not blind-retry
return fallbackRoles; // e.g. roleMapping['_default']
}
} else throw err;
} Prevention
- Enable domain-wide delegation for the service account and set subject to an admin email
- Include admin.directory.group.readonly in the token scopes and enable the Admin SDK API
- Prefer serviceAccount auth so tokens are auto-refreshed instead of static access tokens
- Degrade gracefully: fall back to roleMapping._default when Directory lookups fail
- Keep user emails normalized/validated before passing them as userKey
When it happens
Trigger: getRoles(user) (via rolesPromise) hits the Directory API and receives 401 (expired/invalid token), 403 (service account lacks domain-wide delegation, missing admin.directory.group.readonly scope, or API not enabled), 404 (userKey not found in domain), or 400 (bad userKey/email).
Common situations: Service account without domain-wide delegation or the 'sub' (subject) not set to an admin user; Admin SDK API disabled in Google Cloud project; access token from a different audience/scope; querying a user email outside the Workspace domain; 10s AbortSignal timeout resulting in network failures surfaced separately.
Related errors
- Token exchange failed: ${error}
- Google token exchange failed: ${error}
- Google RBAC roleMapping is required.
- Google Workspace Directory authentication is not configured.
- Google service account token request failed (${response.stat
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/31095f11f2cec5ef.
Report an issue: GitHub.