mastra-ai/mastra · warning · HTTPException
Not found
Error message
Not found
What it means
assertReadAccess throws this 404 when the caller is neither the record's author nor holds a scoped 'read' permission for the resource. A 404 (rather than 403) is intentional: it hides the existence of stored agents/skills from unauthorized callers. It is raised by the favorite/unfavorite/export/get/dependents stored-agent routes and favorite stored-skill route.
Source
Thrown at packages/server/src/server/handlers/authorship.ts:222
const owner = record.authorId ?? null;
if (owner === null) return;
if (record.visibility === 'public') return;
if (hasAdminBypass(requestContext, resource)) return;
const callerAuthorId = getCallerAuthorId(requestContext);
// No authenticated user on the request context means auth is not configured
// (single-user/dev mode). When auth IS configured, coreAuthMiddleware
// rejects unauthenticated requests with 401 before they reach handlers,
// so an absent user here genuinely means no auth provider.
if (!callerAuthorId && !requestContext.get(MASTRA_USER_KEY)) return;
if (callerAuthorId === owner) return;
if (hasScopedPermission({ requestContext, resource, action: 'read', resourceId })) {
return;
}
throw new HTTPException(404, { message: 'Not found' });
}
/**
* Asserts the caller has execute access to the record. Throws 404 if not.
*
* Execute access is granted when:
* - The record has no owner (legacy/public), OR
* - The record is marked `visibility: 'public'`, OR
* - The caller owns the record, OR
* - The caller has admin bypass (`*`, `<resource>:*`, `<resource>:admin`), OR
* - The caller holds `<resource>:execute` / `<resource>:execute:<resourceId>`, OR
* - The caller holds `<resource>:read` / `<resource>:read:<resourceId>`
* (read implies the ability to consume/chat with the resource).
*/
export function assertExecuteAccess(args: {
requestContext: RequestContext;
resource: string;
resourceId?: string;View on GitHub (pinned to 75dd419e61)
Solutions
- Verify the record ID exists and is visible to you — 404 deliberately conflates 'missing' and 'forbidden', so check authorship first.
- Obtain the record from its author or have an admin grant you a scoped read permission for that resource/ID.
- Confirm your auth middleware populates requestContext so hasScopedPermission sees your grants.
- If you are the author, ensure the request is authenticated as the same identity (same author ID) that created the record.
Example fix
// before: assuming 403 for forbidden
if (!res.ok) throw new Error('Forbidden');
// after: treat 404 as 'missing or no access', verify ID/grants
if (res.status === 404) {
const exists = await adminCheck(id);
throw new Error(exists ? 'No read access to this record' : 'Record does not exist');
} Defensive patterns
Strategy: try-catch
Validate before calling
// Client-side pre-check: only request records you authored or know are shared with you
if (!recordIdsKnownVisible.has(id)) {
throw new Error(`Skipping ${id}: not authored by you and not confirmed readable`);
} Try / catch
try {
const agent = await getStoredAgent(id);
} catch (e) {
if (e.status === 404) {
// 404 conflates 'missing' and 'no read access' by design
throw new Error(`Stored agent ${id} does not exist or you lack read access.`);
}
throw e;
} Prevention
- Treat 404 as 'missing OR forbidden' — don't probe IDs to discover existence.
- Share records by adjusting audience/visibility rather than passing raw IDs.
- Ensure auth middleware populates requestContext so scoped read permissions are honored.
- Verify IDs against a list endpoint you're permitted to call before fetching directly.
When it happens
Trigger: GET /stored-agents/:id (or its dependents/export) or POST/DELETE favorite routes where: the record doesn't exist (lookup failed upstream), the caller is not the author, and the caller's requestContext lacks a scoped read permission for that resource.
Common situations: Sharing an agent/skill ID with a teammate who has no read grant; accessing a private record via API with a token lacking read scope; referencing a deleted or never-existing ID; cross-tenant access where the record belongs to another author.
Related errors
- Not found
- Admin access required
- RBAC provider does not support role permission resolution
- Stored agent with id ${storedAgentId} not found
- Model "${modelId}" is not available. Available models: ${ids
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/43c60e7a63a01ba0.
Report an issue: GitHub.