{"record":{"id":"3eafa3cef35d7f50","repo":"mastra-ai/mastra","slug":"modelbyinputtokens-requires-at-least-one-threshold","errorCode":null,"errorMessage":"ModelByInputTokens requires at least one threshold in \"upTo\"","messagePattern":"ModelByInputTokens requires at least one threshold in \"upTo\"","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/memory/src/processors/observational-memory/model-by-input-tokens.ts","lineNumber":32,"sourceCode":"\n  if (!model || typeof model !== 'object') {\n    return false;\n  }\n\n  return (\n    'modelId' in model ||\n    'id' in model ||\n    'providerId' in model ||\n    'provider' in model ||\n    ('doGenerate' in model && 'doStream' in model)\n  );\n}\n\nfunction normalizeThresholds(config: ModelByInputTokensConfig) {\n  const entries = Object.entries(config.upTo);\n\n  if (entries.length === 0) {\n    throw new Error('ModelByInputTokens requires at least one threshold in \"upTo\"');\n  }\n\n  for (const [limitStr, model] of entries) {\n    const limit = Number(limitStr);\n    if (!Number.isFinite(limit) || limit <= 0) {\n      throw new Error(`ModelByInputTokens threshold keys must be positive numbers. Got: ${limitStr}`);\n    }\n\n    if (!isTieredModelTarget(model)) {\n      throw new Error(`ModelByInputTokens requires a valid model target for threshold ${limitStr}`);\n    }\n  }\n\n  return entries.map(([limitStr, model]) => ({ limit: Number(limitStr), model })).sort((a, b) => a.limit - b.limit);\n}\n\nexport class ModelByInputTokens {\n  private readonly thresholds: Array<{ limit: number; model: AgentConfig['model'] }>;","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/processors/observational-memory/model-by-input-tokens.ts#L14-L50","documentation":"ModelByInputTokens is a processor that selects a model based on input token count using a map of thresholds (\"upTo\") keyed by token limits. The constructor normalizes this config, and throws immediately if the upTo map has no entries at all, because there would be no model to resolve to for any input.","triggerScenarios":"Calling `new ModelByInputTokens({ upTo: {} })` or `new ModelByInputTokens({ upTo: {} as any })` — an empty upTo object — during construction.","commonSituations":"Building the config programmatically from environment variables or feature flags where all threshold branches are disabled or the env vars are unset, yielding an empty object; spreading an empty partial config; a refactor that removed the last threshold entry.","solutions":["Add at least one threshold entry to upTo, e.g. { upTo: { 128000: 'openai/gpt-4o' } }","If building config dynamically, add a fallback/default threshold entry before constructing","Guard construction: only instantiate ModelByInputTokens when Object.keys(config.upTo).length > 0"],"exampleFix":"// before\nnew ModelByInputTokens({ upTo: {} });\n// after\nnew ModelByInputTokens({ upTo: { 128000: 'openai/gpt-4o' } });","handlingStrategy":"validation","validationCode":"if (!config.upTo || Object.keys(config.upTo).length === 0) {\n  throw new Error('upTo must contain at least one threshold before constructing ModelByInputTokens');\n}\nconst processor = new ModelByInputTokens(config);","typeGuard":"function hasThresholds(c: { upTo: Record<string, unknown> }): c is { upTo: Record<string, unknown> & { [k: string]: unknown } } {\n  return typeof c.upTo === 'object' && c.upTo !== null && Object.keys(c.upTo).length > 0;\n}","tryCatchPattern":"let processor;\ntry {\n  processor = new ModelByInputTokens(config);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('at least one threshold')) {\n    processor = new ModelByInputTokens({ upTo: { [defaultLimit]: defaultModel } });\n  } else throw e;\n}","preventionTips":["Always define at least one fallback threshold in config templates","Validate upTo keys/values before construction","Avoid spreading optional/partial configs that can leave upTo empty"],"tags":["config","observational-memory","constructor"],"backgroundTag":"empty-required-config","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}