{"record":{"id":"52b98c1f13e524cd","repo":"mastra-ai/mastra","slug":"tokencostcontrol-requires-observability-storage-wi","errorCode":null,"errorMessage":"TokenCostControl requires observability storage with getMetricAggregate support. Configure observability storage on your Mastra instance.","messagePattern":"TokenCostControl requires observability storage with getMetricAggregate support\\. Configure observability storage on your Mastra instance\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/core/src/processors/processors/token-cost-control.ts","lineNumber":283,"sourceCode":"      if (!Number.isFinite(options.warnAtPercent) || options.warnAtPercent <= 0 || options.warnAtPercent >= 100) {\n        throw new Error('TokenCostControl requires warnAtPercent to be a number between 0 and 100 (exclusive)');\n      }\n      this.warnAtPercent = options.warnAtPercent;\n    }\n\n    this.maxCost = options.maxCost;\n    this.scope = options.scope ?? 'resource';\n    this.window = options.window ?? '7d';\n    this.strategy = options.strategy ?? 'block';\n    this.messageTemplate = options.message ?? 'Cost control: estimated cost limit exceeded ({usage}/{limit})';\n    this.includeBreakdown = options.includeBreakdown ?? false;\n  }\n\n  __registerMastra(mastra: Mastra<any, any, any, any, any, any, any, any, any, any>): void {\n    const storage = mastra.getStorage();\n    const obsStorage = storage?.stores?.observability;\n    if (!obsStorage || typeof obsStorage.getMetricAggregate !== 'function') {\n      throw new Error(\n        `TokenCostControl requires observability storage with getMetricAggregate support. ` +\n          'Configure observability storage on your Mastra instance.',\n      );\n    }\n    this.observabilityStorage = obsStorage;\n    this.logger = mastra.getLogger();\n  }\n\n  private resolveScopeFilter(\n    requestContext?: RequestContext,\n    traceId?: string,\n  ): { filter: Record<string, string>; scopeKey?: string } | undefined {\n    if (this.scope === 'run') {\n      if (!traceId) return undefined;\n      return { filter: { traceId } };\n    }\n\n    // Reserved keys from RequestContext take precedence (set by auth middleware).","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/processors/processors/token-cost-control.ts#L265-L301","documentation":"TokenCostControl queries historical usage via the observability store's `getMetricAggregate`. In `__registerMastra` (called when the processor is attached to a Mastra instance), it checks that storage exists and exposes that method; if not, it throws, because without observability storage it cannot aggregate token/cost metrics. Note the check is for `getMetricAggregate` support — older storage adapters lack it.","triggerScenarios":"Registering TokenCostControl on a Mastra instance created without storage (`new Mastra({ ... })` with no `storage`), with a storage backend whose observability store doesn't implement `getMetricAggregate` (outdated @mastra/core storage adapters or third-party stores), or `mastra.getStorage()` returning undefined.","commonSituations":"Deployments where storage was configured for workflows/threads but not observability, upgrading core without upgrading storage packages (version mismatch), in-memory setups that never configured observability storage, and tests using minimal Mastra instances.","solutions":["Configure storage with an observability store on your Mastra instance: `new Mastra({ storage: new LibSQLStore(...), observability: {...} })` (per current docs).","Upgrade @mastra/core and your storage package to versions where the observability store implements `getMetricAggregate`.","Verify with `mastra.getStorage()?.stores?.observability?.getMetricAggregate` before registering the processor.","In tests/minimal setups, swap TokenCostControl for a processor that doesn't need metric aggregation."],"exampleFix":"// before\nnew Mastra({ agents }); // no storage\n// after\nnew Mastra({ agents, storage: new LibSQLStore({ url: process.env.DB_URL }), observability: { default: { enabled: true } } });","handlingStrategy":"validation","validationCode":"const obs = mastra.getStorage()?.stores?.observability;\nif (!obs || typeof obs.getMetricAggregate !== 'function') {\n  throw new Error('TokenCostControl requires observability storage with getMetricAggregate support');\n}","typeGuard":"function supportsMetricAggregate(s: unknown): s is { getMetricAggregate: (...args: unknown[]) => Promise<unknown> } {\n  return typeof (s as any)?.getMetricAggregate === 'function';\n}","tryCatchPattern":"try {\n  mastra.register(processor); // triggers __registerMastra\n} catch (e) {\n  if (e.message.includes('observability storage')) {\n    console.error('Enable observability storage on Mastra before using TokenCostControl');\n    processors = processors.filter(p => p !== processor);\n  } else throw e;\n}","preventionTips":["Always configure storage (with observability store) on Mastra instances in production and tests.","Keep @mastra/core and storage packages on matching versions so getMetricAggregate exists.","Probe `mastra.getStorage()?.stores?.observability` during app startup and fail fast with a clear message.","Only register TokenCostControl when observability is part of the deployment's feature set."],"tags":["storage","observability","configuration","registration"],"backgroundTag":"missing-observability-storage","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}