{"record":{"id":"9126159eb724b056","repo":"mastra-ai/mastra","slug":"modelbyinputtokens-requires-inputtokens-for-resolu","errorCode":null,"errorMessage":"ModelByInputTokens requires inputTokens for resolution","messagePattern":"ModelByInputTokens requires inputTokens for resolution","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/memory/src/processors/observational-memory/observational-memory.ts","lineNumber":761,"sourceCode":"  /**\n   * Wait for any in-flight async buffering operations for the given thread/resource.\n   * Used by server endpoints to block until buffering completes so the UI can get final state.\n   */\n  async waitForBuffering(\n    threadId: string | null | undefined,\n    resourceId: string | null | undefined,\n    timeoutMs = 30000,\n  ): Promise<void> {\n    return BufferingCoordinator.awaitBuffering(threadId, resourceId, this.scope, timeoutMs);\n  }\n\n  private getConcreteModel(\n    model: ObservationalMemoryModel,\n    inputTokens?: number,\n  ): Exclude<ObservationalMemoryModel, ModelByInputTokens> {\n    if (model instanceof ModelByInputTokens) {\n      if (inputTokens === undefined) {\n        throw new Error('ModelByInputTokens requires inputTokens for resolution');\n      }\n      return model.resolve(inputTokens) as Exclude<ObservationalMemoryModel, ModelByInputTokens>;\n    }\n\n    return model as Exclude<ObservationalMemoryModel, ModelByInputTokens>;\n  }\n\n  private getModelToResolve(\n    model: ObservationalMemoryModel,\n    inputTokens?: number,\n  ): Parameters<typeof resolveModelConfig>[0] {\n    const concreteModel = this.getConcreteModel(model, inputTokens);\n\n    if (Array.isArray(concreteModel)) {\n      return (concreteModel[0]?.model ?? 'unknown') as Parameters<typeof resolveModelConfig>[0];\n    }\n    if (typeof concreteModel === 'function') {\n      // Wrap to handle functions that may return ModelWithRetries[]","sourceCodeStart":743,"sourceCodeEnd":779,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/processors/observational-memory/observational-memory.ts#L743-L779","documentation":"ObservationalMemory can be configured with a ModelByInputTokens, which selects a concrete language model dynamically based on the size of the current input (token count). During resolution via getConcreteModel, the caller must supply the inputTokens count; without it there is no way to pick the right model tier, so the library throws instead of guessing. This is a programming error in the internal call path, surfacing when the token count was never computed or propagated.","triggerScenarios":"getConcreteModel is called with a ModelByInputTokens instance and inputTokens === undefined. This happens when the internal concreteModel path resolves the model before any message/token counting has occurred (e.g. no stored messages, or a call path that skips token estimation), or if a custom subclass/caller invokes getConcreteModel without the second argument.","commonSituations":"Calling memory APIs (remember/recall) on an empty thread where no token usage has been recorded yet; custom code extending ObservationalMemory that calls getConcreteModel directly; a ModelByInputTokens configured without any messages in the thread so the resolver has no token count.","solutions":["Ensure the call is made on a thread/context that has messages so inputTokens can be computed before model resolution.","If you call getConcreteModel yourself, always pass the computed inputTokens value.","Replace ModelByInputTokens with a concrete static model if you don't need dynamic tiering — then resolution never needs inputTokens.","Upgrade/check package version; if this occurs on normal empty-thread calls it may be a bug — file an issue with a reproduction."],"exampleFix":"// before\nconst model = memory.getConcreteModel(new ModelByInputTokens({ small: m1, large: m2 }));\n// after\nconst inputTokens = estimateTokens(messages);\nconst model = memory.getConcreteModel(new ModelByInputTokens({ small: m1, large: m2 }), inputTokens);","handlingStrategy":"validation","validationCode":"if (model instanceof ModelByInputTokens) {\n  const tokens = estimateInputTokens(thread.messages);\n  if (tokens === undefined) throw new Error('Cannot resolve ModelByInputTokens: no token count available');\n}","typeGuard":"function isResolvable(model: ObservationalMemoryModel, inputTokens?: number): boolean {\n  return !(model instanceof ModelByInputTokens) || inputTokens !== undefined;\n}","tryCatchPattern":null,"preventionTips":["Prefer a static concrete model unless dynamic tiering is required.","Only use ModelByInputTokens on threads that contain messages so token counts exist.","Never call getConcreteModel directly from application code."],"tags":["configuration","model-resolution","observational-memory"],"backgroundTag":"missing-required-argument","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}