{"record":{"id":"bf5fd01f1377b3f4","repo":"mastra-ai/mastra","slug":"factory-review-phase-requires-a-selected-session-m","errorCode":null,"errorMessage":"Factory review phase requires a selected session model.","messagePattern":"Factory review phase requires a selected session model\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/processor.ts","lineNumber":103,"sourceCode":"  role: string;\n  ruleSetVersion: string;\n  status: 'active';\n};\n\ntype ActivePhaseSnapshotValue =\n  | (ActivePhaseSnapshotBase & { board: 'work' })\n  | (ActivePhaseSnapshotBase & { board: 'review' } & RuntimeSnapshot);\n\ntype PhaseSnapshotValue = ActivePhaseSnapshotValue | { bindingId?: string; status: 'none' };\n\nfunction reviewRuntimeFromRequestContext(requestContext: ComputeStateSignalArgs['requestContext']): RuntimeSnapshot {\n  if (!requestContext || typeof requestContext.get !== 'function') {\n    throw new Error('Factory review phase requires a controller request context.');\n  }\n  const context = requestContext.get<'controller', AgentControllerRequestContext<MastraCodeState>>('controller');\n  const modelId = context?.session?.modelId.trim();\n  if (!modelId) {\n    throw new Error('Factory review phase requires a selected session model.');\n  }\n  return { modelId, thinkingLevel: resolveRequestThinkingLevel(context) };\n}\n\nfunction workItemSourceKey(item: WorkItemRow): string | null {\n  const source = item.externalSource;\n  return source ? `${source.integrationId}:${source.type}:${source.externalId}` : null;\n}\n\nfunction boardForItem(item: WorkItemRow): FactoryRuleBoard {\n  return item.externalSource?.type === 'pull-request' ? 'review' : 'work';\n}\n\nfunction boundedError(value: unknown): FactoryRuleJsonValue {\n  const message = value instanceof Error ? value.message : typeof value === 'string' ? value : 'Tool execution failed.';\n  return { message: message.slice(0, 2_000) };\n}\n","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/processor.ts#L85-L121","documentation":"The review phase needs a concrete modelId to run the review generation, read from the controller session (context.session.modelId). If the controller context exists but no model was selected for the session (empty or whitespace-only modelId), the library throws rather than guessing a model, because review output depends on the session's chosen model and thinking level.","triggerScenarios":"The agent controller session was created without a model selection (session.modelId empty/whitespace) when the review phase's runtime snapshot was computed — e.g. session initialized lazily before the client picked a model, or the model was cleared.","commonSituations":"Client never sent a model selection before triggering review; default-model configuration missing on the session; session state persisted before the modelId field existed (schema migration); UI flows that start review before model setup completes.","solutions":["Set a model on the controller session (session.modelId) before entering the review phase.","Configure a default model for sessions so modelId is always populated.","Check client wiring so the model selection is committed to session state before review is triggered.","For old persisted sessions, backfill session.modelId or recreate the session."],"exampleFix":"// before: review triggered on a session with no model\nawait startReviewPhase({ sessionId }); // session.modelId === ''\n// after: select model first\nawait controller.selectModel({ sessionId, modelId: 'openai/gpt-4o' });\nawait startReviewPhase({ sessionId });","handlingStrategy":"validation","validationCode":"const ctx = requestContext.get('controller');\nconst modelId = ctx?.session?.modelId?.trim();\nif (!modelId) throw new Error('select a session model before entering the review phase');","typeGuard":"function hasSelectedModel(rc) {\n  const ctx = rc?.get?.('controller');\n  return typeof ctx?.session?.modelId === 'string' && ctx.session.modelId.trim().length > 0;\n}","tryCatchPattern":"try {\n  const snapshot = reviewRuntimeFromRequestContext(requestContext);\n} catch (e) {\n  if (String(e?.message).includes('requires a selected session model')) {\n    await selectDefaultModel(controllerSession); // apply org default before retry\n    return reviewRuntimeFromRequestContext(requestContext);\n  } else throw e;\n}","preventionTips":["Configure a default model so sessions always have modelId set","Gate review-phase entry in the UI on a committed model selection","Backfill session.modelId for sessions persisted by older schemas","Trim/validate modelId at session creation time to reject whitespace-only values"],"tags":["factory","model-selection","session","review-phase"],"backgroundTag":"missing-model-selection","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}