eyaltoledano/claude-task-master · error · TaskMasterError

API_ERROR

API_ERROR

Error message

`Failed to fetch organizations: ${error.message}`

What it means

Thrown by OrganizationService.getOrganizations when the Supabase query against the user_accounts view returns an error object. The raw Supabase/Postgres error message is embedded in the thrown TaskMasterError, with code API_ERROR and context {operation:'getOrganizations'}. It signals a database/API-level failure (schema, RLS, or network), not an empty result set.

Source

Thrown at packages/tm-core/src/modules/auth/services/organization.service.ts:69

	constructor(private supabaseClient: SupabaseClient<Database>) {}

	/**
	 * Get all organizations for the authenticated user
	 */
	async getOrganizations(): Promise<Organization[]> {
		try {
			// The user is already authenticated via the Authorization header
			// Query the user_accounts view/table (filtered by RLS for current user)
			const { data, error } = await this.supabaseClient
				.from('user_accounts')
				.select(`
					id,
					name,
					slug
				`);

			if (error) {
				throw new TaskMasterError(
					`Failed to fetch organizations: ${error.message}`,
					ERROR_CODES.API_ERROR,
					{ operation: 'getOrganizations' },
					error
				);
			}

			if (!data || data.length === 0) {
				this.logger.debug('No organizations found for user');
				return [];
			}

			// Map to our Organization interface
			return data.map((org) => ({
				id: org.id ?? '',
				name: org.name ?? '',
				slug: org.slug ?? org.id ?? '' // Use ID as fallback if slug is null
			}));

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Read error.cause (the embedded Supabase error) for the exact Postgres/RLS message
  2. Re-authenticate to refresh an expired JWT, then retry
  3. Check the user_accounts view exists in the current schema (migrations may have renamed it)
  4. Verify network connectivity / Supabase project status
  5. If RLS-related, confirm the user has an active user_accounts row (account membership)
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight session check before querying organizations
const { data: sessionData, error: sessionErr } = await supabase.auth.getSession();
if (sessionErr || !sessionData.session) {
  throw new Error('Not authenticated: run `tm auth login` before fetching organizations');
}

Type guard

function isTaskMasterApiError(e: unknown): e is TaskMasterError {
  return e instanceof TaskMasterError && e.code === ERROR_CODES.API_ERROR;
}

Try / catch

try {
  const orgs = await orgService.getOrganizations();
} catch (e) {
  if (isTaskMasterApiError(e)) {
    const cause = e.cause as { code?: string; message?: string };
    if (cause?.code === '42P01') console.error('user_accounts view missing — schema out of date');
    else if (cause?.code === '42501') console.error('RLS denied access — check account membership');
    else console.error('Fetch organizations failed:', cause?.message ?? e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling getOrganizations() when the user_accounts table/view does not exist or was renamed, RLS denies access to the current user, the JWT/session is expired or invalid, or the Supabase request fails (network error, 5xx).

Common situations: Expired auth token after idle time; server schema migration renamed user_accounts; user's membership rows deleted so RLS rejects; offline or corporate proxy blocking the Supabase host.

Related errors


AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29). Data as JSON: /api/errors/3f00635cdae030b0. Report an issue: GitHub.