mastra-ai/mastra · error

Subconscious curate requires organizationId in the request c

Error message

Subconscious curate requires organizationId in the request context.

What it means

resolveScope in the Subconscious curator requires requestContext.organizationId to canonicalize the knowledge scope when handling reflection-committed events. Missing/blank organizationId means curate (pin/edit/unpin) cannot be scoped, so it throws.

Source

Thrown at packages/memory/src/processors/observational-memory/subconscious/curate.ts:29

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

const CURATION_AGENT = 'curate';
const DEFAULT_INSTRUCTIONS = `Maintain durable scoped knowledge from the committed observation worklist.

Use the read tools to inspect existing nodes, knowledge records, mentions, backlinks, and long-form node content. Use the write tools to merge true duplicates, repair names and links, soft-delete superseded knowledge records, rescope knowledge records only when justified and permitted by their ceilings, and synthesize useful node content. Never restore deleted knowledge records. Never invent provenance, capture timestamps, scopes, ceilings, IDs, or versions; those are enforced by code. Resolve optimistic-concurrency conflicts by reading the latest record and retrying the intended mutation. Keep the reserved capture-guidance node concise and update it only with durable guidance that will improve future capture.

For each significant entity node touched by a KnowledgeRecord in the current worklist, including people, projects, pull requests, issues, repositories, documents, and organizations, maintain a short entity description; do not walk nodes outside the worklist for this. Use the supplied record and read the named node once; do not search or browse unless its identity is ambiguous. Describe what the entity is, its current state, and links to its real-world object, then write it with knowledge_write_node_description, which always requires expectedVersion from the node you just read; after a version conflict, re-read the node and regenerate the description from its current state before retrying. If the node does not exist yet, create it first with knowledge_write_node_content, then re-read it for its fresh version before writing the description. Write one or two plain-text sentences, roughly 40 to 75 tokens; storage rejects any description over its hard length cap, so keep them tight and put long-form detail in node content instead. Include links only from the entity's own records or observations that explicitly associate the link with that entity; never invent a URL, identifier, file path, or provenance. Leave long-form node content alone unless you are synthesizing it deliberately; never shrink content into a synopsis. For entity-description maintenance only, skip low-signal nodes with only a trivial record, any system-kind node, and the reserved capture-guidance node.

Process the worklist in ID order. Every time you finish processing a KnowledgeRecord, include <curation-complete through="RECORD_ID" /> in your next text response with that record's ID. The latest marker is your acknowledged cursor, so progress survives if you run out of steps mid-batch. Your final response must end with the marker for the last KnowledgeRecord you fully processed. If you cannot finish the batch, acknowledge only the last KnowledgeRecord you did finish. Do not emit a completion marker when no KnowledgeRecord was fully processed.`;

export const PINNED_INSTRUCTIONS = `Maintain the pin set with knowledge_pin, knowledge_edit_pin, and knowledge_unpin. Pinned entries are delivered to the main agent on every turn, so they cost tokens permanently and must stay short. Pin only knowledge that should apply without being asked for, such as standing instructions, durable preferences, and hard constraints. Pin only knowledge that is BOTH costly to rediscover AND not the kind of thing a future agent would think to search for; anything a reminder can surface on demand does not belong in the pin set. Unpin an entry as soon as it stops being unconditionally true.`;

function resolveScope(context: ReflectionCommittedContext): KnowledgeScope {
  const organizationId = context.requestContext?.get('organizationId');
  if (typeof organizationId !== 'string' || !organizationId.trim()) {
    throw new Error('Subconscious curate 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` tells the agent the
 * worklist was truncated; the cursor it advances lets the next cycle pick up the remainder.
 */
const MAX_WORKLIST_RECORDS = 1000;

async function readWorklist(store: KnowledgeStorage, sourceThreadId: string, scope: KnowledgeScope, after?: string) {
  const records = [];
  let cursor = after;
  do {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Set organizationId on the request context for all flows that can trigger reflection/curation
  2. Propagate requestContext from the request into background reflection jobs
  3. If curation isn't needed, disable Subconscious curate instead of leaving context incomplete

Example fix

// before
await memory.reflect({ threadId }); // no context
// after
await memory.reflect({ threadId, requestContext: rc.with('organizationId', 'org_123') });
Defensive patterns

Strategy: validation

Validate before calling

if (typeof requestContext?.get('organizationId') !== 'string' || !requestContext.get('organizationId')?.trim()) throw new Error('organizationId required for curate');

Type guard

const hasOrg = (rc?: RequestContext) => typeof rc?.get('organizationId') === 'string' && !!rc.get('organizationId')!.trim();

Try / catch

try { await handleCurate(ctx) } catch (e) { if (String(e).includes('organizationId')) { logMissingContext(e); } else throw e; }

Prevention

When it happens

Trigger: A reflectionCommitted event triggers the curator while the originating context lacks a non-empty organizationId — e.g. background reflection runs re-using a context where organizationId was never set.

Common situations: Cron/background reflection jobs not propagating requestContext; multi-tenant apps with one path missing organizationId; upgrades introducing scoped curation.

Related errors


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