mastra-ai/mastra · critical · Error

Subconscious learn requires organizationId in the request co

Error message

Subconscious learn requires organizationId in the request context.

What it means

The subconscious learner derives the knowledge scope from the request context, and organizationId is mandatory: the scope is anchored at org:<organizationId>. If requestContext.get('organizationId') is missing, empty, or not a string, resolveScope throws before any learning happens. This guarantees knowledge is always scoped to a tenant and never leaked across organizations.

Source

Thrown at packages/memory/src/processors/observational-memory/subconscious/learn.ts:34

import { resolveKnowledgeResourceId } from './scope';
import type { ResolvedSubconsciousAgent, ResolvedSubconsciousConfig } from './types';

const LEARN_AGENT = 'learn';
const ULID_ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
const DEFAULT_INSTRUCTIONS = `Learn reusable skills from the full pre-reflection observations and pending knowledge records.

A skill is a repeatable procedure with ordered actions, a trigger or context, and a success or recovery outcome. Do not learn one-off events, isolated preferences, knowledge records, or procedures supported by fewer than two distinct pending knowledge records. Search existing kind:skill nodes by exact name before writing so updates extend one skill rather than creating duplicates.

Use knowledge_record_skill for every skill creation or evidence update. It validates the evidence frontier and writes retry-safe evidence. You may use the other scoped knowledge tools for research and maintenance, but never restore deleted records, invent provenance or versions, or write outside the source scope.

Process pending records in ID order. End with <learning-complete through="RECORD_ID" /> naming the last pending record you reviewed, even when no reusable skill was found. Acknowledge only records you fully reviewed.`;

type LearnerState = { recordedName?: string };

function resolveScope(context: ReflectionCommittedContext): KnowledgeScope {
  const organizationId = context.requestContext?.get('organizationId');
  if (typeof organizationId !== 'string' || !organizationId.trim()) {
    throw new Error('Subconscious learn requires organizationId in the request context.');
  }
  return canonicalizeKnowledgeScope([
    `org:${organizationId}`,
    `resource:${resolveKnowledgeResourceId(context.requestContext, context.resourceId)}`,
    `thread:${context.parentThreadId}`,
  ]);
}

/** Upper bound on records pulled into a single reflection prompt; `hasMore` signals truncation. */
const MAX_WORKLIST_RECORDS = 1000;

async function readWorklist(store: KnowledgeStorage, sourceThreadId: string, scope: KnowledgeScope, after?: string) {
  const records: KnowledgeRecord[] = [];
  let cursor = after;
  do {
    const page = await store.knowledgeBySource({ sourceThreadId, scope, after: cursor, limit: 100 });
    records.push(...page.records);
    cursor = page.nextCursor;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass requestContext: new Map([['organizationId', orgId]]) (or equivalent) with a non-empty string organizationId when running the processor/agent
  2. Audit context-construction code paths so every invocation includes the tenant's organizationId
  3. Add a startup assertion/log for missing organizationId in dev to fail fast before reflection

Example fix

// before
await memory.processReflection({ context: { resourceId, parentThreadId } });
// after
await memory.processReflection({
  context: { resourceId, parentThreadId, requestContext: new Map([['organizationId', 'org_123']]) },
});
Defensive patterns

Strategy: validation

Validate before calling

function assertOrgContext(requestContext?: Map<string, unknown> | undefined): string {
  const orgId = requestContext?.get('organizationId');
  if (typeof orgId !== 'string' || !orgId.trim()) throw new Error('organizationId required in requestContext');
  return orgId;
}

Type guard

function hasOrgContext(ctx: unknown): ctx is { requestContext: Map<string, string> & { get(k: 'organizationId'): string } } {
  const orgId = (ctx as any)?.requestContext?.get?.('organizationId');
  return typeof orgId === 'string' && !!orgId.trim();
}

Try / catch

try {
  await memory.processReflection(args);
} catch (e) {
  if (e instanceof Error && e.message.includes('requires organizationId')) {
    // attach tenant context and requeue the reflection
  } else throw e;
}

Prevention

When it happens

Trigger: Running an agent/processor with a requestContext that lacks an organizationId entry, passing an empty string or whitespace-only value, or constructing the ReflectionCommittedContext manually without requestContext.

Common situations: Local development where multi-tenant context plumbing is skipped; background jobs that build contexts by hand; upgrading the observational-memory processor without updating call sites to supply tenant context.

Related errors


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