{"record":{"id":"fe82c775a651a538","repo":"Wei-Shaw/sub2api","slug":"failed-to-get-usage-trend","errorCode":null,"errorMessage":"failed to get usage trend","messagePattern":"failed to get usage trend","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"backend/internal/handler/admin/dashboard_snapshot_v2_handler.go","lineNumber":193,"sourceCode":"\n\tif includeTrend {\n\t\ttrend, _, err := h.getUsageTrendCached(\n\t\t\tctx,\n\t\t\tstartTime,\n\t\t\tendTime,\n\t\t\tgranularity,\n\t\t\tfilters.UserID,\n\t\t\tfilters.APIKeyID,\n\t\t\tfilters.AccountID,\n\t\t\tfilters.GroupID,\n\t\t\tfilters.Model,\n\t\t\tfilters.RequestType,\n\t\t\tfilters.Stream,\n\t\t\tfilters.BillingType,\n\t\t\tfilters.UpstreamModelMismatch,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, errors.New(\"failed to get usage trend\")\n\t\t}\n\t\tresp.Trend = trend\n\t}\n\n\tif includeModels {\n\t\tmodels, _, err := h.getModelStatsCached(\n\t\t\tctx,\n\t\t\tstartTime,\n\t\t\tendTime,\n\t\t\tfilters.UserID,\n\t\t\tfilters.APIKeyID,\n\t\t\tfilters.AccountID,\n\t\t\tfilters.GroupID,\n\t\t\tusagestats.ModelSourceRequested,\n\t\t\tfilters.RequestType,\n\t\t\tfilters.Stream,\n\t\t\tfilters.BillingType,\n\t\t\tfilters.UpstreamModelMismatch,","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/Wei-Shaw/sub2api/blob/073e92d17178a1ccdb0a27017f572f10c9c7ab62/backend/internal/handler/admin/dashboard_snapshot_v2_handler.go#L175-L211","documentation":"Returned while assembling the v2 dashboard snapshot when includeTrend is true and h.getUsageTrendCached(...) fails. The cached helper wraps the usage-stats trend query; on failure the raw error is dropped and replaced with this generic message. Almost always a database/aggregation failure, not a filter syntax problem.","triggerScenarios":"GET dashboard snapshot v2 with the trend section included over a date range where the trend aggregation query fails (DB outage, timeout, malformed time-bucket parameters after the range parse).","commonSituations":"Very wide date ranges with fine granularity producing huge GROUP BY queries; DB maintenance windows; stale trend cache interacting with an evicted/expired entry.","solutions":["Retry with a narrower date range or coarser granularity to reduce aggregation cost","Check backend logs for the underlying trend query error","Verify the usage-stats store is healthy (connectivity, timeouts, disk)","Temporarily exclude the trend section from the snapshot while diagnosing"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Cap request cost before calling\nconst days = (end - start) / 86400000;\nif (includeTrend && days > 90 && granularity === 'hour') throw new Error('range too wide; coarsen granularity');","typeGuard":null,"tryCatchPattern":"// TS\ntry { trend = await getSnapshotV2({ includeTrend: true, start, end, granularity }); }\ncatch (e) {\n  if (e.message === 'failed to get usage trend') {\n    trend = await withBackoff(() => getSnapshotV2({ includeTrend: true, start, end, granularity: 'day' }));\n  } else throw e;\n}","preventionTips":["Bound date range × granularity before requesting trends","Retry transient failures with backoff rather than surfacing them to users","Watch backend slow-query logs for trend aggregations as data grows"],"tags":["dashboard","usage-trend","database","admin"],"backgroundTag":null,"analyzedSha":"073e92d17178a1ccdb0a27017f572f10c9c7ab62","analyzedAt":"2026-08-15T14:33:00.750Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}