mastra-ai/mastra · error · HTTPException

Stored resource not found

Error message

Stored resource not found

What it means

After resolving a stored resource (e.g. an agent version), assertStoredResourceScope verifies the resource's metadata matches the caller's resolved resource scope. If the stored resource's scope metadata key does not equal the requested scope value, it throws HTTP 404 so the existence of out-of-scope resources is not revealed. This is an isolation guard against cross-tenant/cross-resource access.

Source

Thrown at packages/server/src/server/utils.ts:114

    return metadata;
  }

  return {
    ...(metadata ?? {}),
    [scope.metadataKey]: scope.value,
  };
}

export function assertStoredResourceScope(
  resource: StoredResourceLike | null | undefined,
  scope: StoredResourceScope | undefined,
): void {
  if (!resource || !scope) {
    return;
  }

  if (resource.metadata?.[scope.metadataKey] !== scope.value) {
    throw new HTTPException(404, { message: 'Stored resource not found' });
  }
}

/**
 * Check if a schema looks like a processor step schema.
 * Processor step schemas are discriminated unions on 'phase' with specific values.
 */
function looksLikeProcessorStepSchema(schema: PublicSchema<unknown> | undefined): boolean {
  if (!schema) return false;

  try {
    const jsonSchema = standardSchemaToJSONSchema(toStandardSchema(schema)) as Record<string, unknown> | undefined;
    if (!jsonSchema) return false;

    // Check for discriminated union pattern: anyOf/oneOf with phase discriminator
    const variants = (jsonSchema.anyOf || jsonSchema.oneOf) as Array<Record<string, unknown>> | undefined;
    if (!variants || !Array.isArray(variants)) return false;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Send the correct resource id (matching the one the resource was created with) in the request header
  2. Verify the stored record's metadata contains the expected scope key/value (fix data if it was migrated incorrectly)
  3. If the resource genuinely should be accessible, re-create it under the correct scope instead of editing metadata ad hoc

Example fix

// before
curl -H 'x-mastra-resource-id: tenant-2' http://localhost:4111/api/agents/myAgent/versions/v1
// after
curl -H 'x-mastra-resource-id: tenant-1' http://localhost:4111/api/agents/myAgent/versions/v1
Defensive patterns

Strategy: type-guard

Validate before calling

const scoped = versions.filter(v => v.metadata?.[scopeKey] === myResourceId);
// only request ids present in `scoped`

Type guard

function isVersionInScope(v: { metadata?: Record<string, unknown> }, key: string, value: string): boolean {
  return v.metadata?.[key] === value;
}

Try / catch

try {
  await activateVersion(id);
} catch (e) {
  if (isHttp404(e)) { /* treat as not-visible-in-scope, do not retry */ }
  else throw e;
}

Prevention

When it happens

Trigger: Requesting an agent version whose metadata[scopeKey] differs from the caller's scope value — e.g. GET/ACTIVATE/RESTORE/DELETE on a version id created under a different resource id, or after the caller's resource-id header changed.

Common situations: Multi-tenant setups where a client switches tenants but caches old version ids; copying database records between environments without migrating the scope metadata key on stored resources; the caller sending the wrong x-mastra-resource-id for the resource they reference.

Related errors


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