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

  1. Read the HTTP status in the message: 401 => refresh/fix the token; 403 => fix delegation/scopes; 404/400 => check userKey.
  2. For service accounts, enable domain-wide delegation in Workspace Admin and set subject to an admin email with group read rights.
  3. 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.
  4. Verify the user's email (or getUserKey result) belongs to the Workspace domain and is a valid userKey.
  5. Confirm the Admin SDK Directory API is enabled for the project in Google Cloud Console.
  6. 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

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


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