{"record":{"id":"308bfd6566b47ba5","repo":"microsoft/aspire","slug":"dimension-limit-of-telemetryrepositorylimits","errorCode":null,"errorMessage":"Dimension limit of {TelemetryRepositoryLimits.MaxDimensionCount} reached.","messagePattern":"Dimension limit of (.+?) reached\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Aspire.Dashboard/Otlp/Storage/SqliteTelemetryRepository.Metrics.Writes.cs","lineNumber":511,"sourceCode":"        {\n            candidates = [];\n            ingestionState.Dimensions.Add(cacheKey, candidates);\n        }\n\n        foreach (var candidate in candidates)\n        {\n            if (candidate.Attributes.SequenceEqual(attributes))\n            {\n                return candidate;\n            }\n        }\n\n        var knownAttributeValues = ingestionState.KnownAttributeValues[instrumentId];\n        knownAttributeValues.ValidateDimension(attributes);\n        var dimensionCount = ingestionState.DimensionCounts[instrumentId];\n        if (dimensionCount >= TelemetryRepositoryLimits.MaxDimensionCount)\n        {\n            throw new InvalidOperationException($\"Dimension limit of {TelemetryRepositoryLimits.MaxDimensionCount} reached.\");\n        }\n        knownAttributeValues.AddDimension(attributes);\n        var dimension = new MetricDimensionState { Attributes = attributes };\n        ingestionState.PendingDimensions.Add(new PendingMetricDimension(instrumentId, attributeHash, dimension));\n        ingestionState.PendingDimensionAttributes.AddRange(attributes.Select((attribute, ordinal) => new PendingMetricDimensionAttribute(\n            dimension,\n            ordinal,\n            attribute.Key,\n            attribute.Value)));\n\n        candidates.Add(dimension);\n        ingestionState.DimensionCounts[instrumentId] = dimensionCount + 1;\n        return dimension;\n    }\n\n    private static void InsertMetricDimensions(\n        SqliteConnection connection,\n        IDbTransaction transaction,","sourceCodeStart":493,"sourceCodeEnd":529,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Dashboard/Otlp/Storage/SqliteTelemetryRepository.Metrics.Writes.cs#L493-L529","documentation":"The repository limits the number of unique metric attribute (dimension) combinations per instrument to TelemetryRepositoryLimits.MaxDimensionCount. GetOrAddMetricDimension checks the per-instrument dimension count before adding a new one and throws InvalidOperationException when the cap is reached, guarding against unbounded high-cardinality storage.","triggerScenarios":"AddMetricToDatabase -> GetOrAddMetricDimension for an instrument whose ingestionState.DimensionCounts[instrumentId] is already >= MaxDimensionCount while the incoming point has a new attribute combination.","commonSituations":"Metrics with high-cardinality attributes (user ids, urls, container ids, correlation ids); a service under attack or a load test hammering unique tag values; long dashboard sessions accumulating dimensions from many emitters.","solutions":["Remove or bound high-cardinality attributes on your metrics; keep tag values from small fixed sets.","Increase TelemetryRepositoryLimits.MaxInstrumentCount/MaxDimensionCount limits via dashboard configuration if your workload is legitimately dimensional.","Restart the dashboard to clear in-memory ingestion state after fixing the emitter.","Use OTel attribute-per-cardinality guidance (e.g. drop url, user id attributes from metrics)."],"exampleFix":"// before\ncounter.Add(1, new KeyValuePair<string, object?>(\"user.id\", userId)); // unbounded\n// after\ncounter.Add(1, new KeyValuePair<string, object?>(\"user.tier\", userTier)); // bounded set","handlingStrategy":"try-catch","validationCode":"// audit metric attributes for unbounded values before export\nforeach (var attr in attributes)\n    if (attr.Value is string s && IsHighCardinality(s))\n        logger.LogWarning(\"Attribute {Key} looks high-cardinality\", attr.Key);","typeGuard":null,"tryCatchPattern":"try\n{\n    await repo.AddMetricsAsync(request);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Dimension limit\"))\n{\n    logger.LogWarning(ex, \"Metric cardinality limit reached for instrument.\");\n}","preventionTips":["Avoid ids, urls, emails, and timestamps as metric attributes.","Keep attribute values in small fixed sets.","Raise TelemetryRepositoryLimits deliberately and knowingly, not as a first resort.","Load-test metric cardinality before production."],"tags":["metrics","cardinality","limits","otlp"],"backgroundTag":"value-out-of-range","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}