{"record":{"id":"91c1f4c8f2c514b5","repo":"vitessio/vitess","slug":"invalid-metric-name-s","errorCode":null,"errorMessage":"invalid metric name: %s","messagePattern":"invalid metric name: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtctl/grpcvtctldserver/server.go","lineNumber":2112,"sourceCode":"\tspan, ctx := trace.NewSpan(ctx, \"VtctldServer.UpdateThrottlerConfig\")\n\tdefer span.Finish()\n\n\tdefer panicHandler(&err)\n\n\tif req.Enable && req.Disable {\n\t\treturn nil, errors.New(\"--enable and --disable are mutually exclusive\")\n\t}\n\n\tif req.MetricName != \"\" && !base.KnownMetricNames.Contains(base.MetricName(req.MetricName)) {\n\t\treturn nil, fmt.Errorf(\"unknown metric name: %s\", req.MetricName)\n\t}\n\n\tif len(req.AppCheckedMetrics) > 0 {\n\t\tspecifiedMetrics := map[base.MetricName]bool{}\n\t\tfor _, metricName := range req.AppCheckedMetrics {\n\t\t\t_, knownMetric, err := base.DisaggregateMetricName(metricName)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid metric name: %s\", metricName)\n\t\t\t}\n\t\t\tif _, ok := specifiedMetrics[knownMetric]; ok {\n\t\t\t\treturn nil, fmt.Errorf(\"duplicate metric name: %s\", knownMetric)\n\t\t\t}\n\t\t\tspecifiedMetrics[knownMetric] = true\n\t\t}\n\t}\n\n\tupdate := func(throttlerConfig *topodatapb.ThrottlerConfig) *topodatapb.ThrottlerConfig {\n\t\tif throttlerConfig == nil {\n\t\t\tthrottlerConfig = &topodatapb.ThrottlerConfig{}\n\t\t}\n\t\tif throttlerConfig.ThrottledApps == nil {\n\t\t\tthrottlerConfig.ThrottledApps = make(map[string]*topodatapb.ThrottledAppRule)\n\t\t}\n\t\tif throttlerConfig.AppCheckedMetrics == nil {\n\t\t\tthrottlerConfig.AppCheckedMetrics = make(map[string]*topodatapb.ThrottlerConfig_MetricNames)\n\t\t}","sourceCodeStart":2094,"sourceCodeEnd":2130,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtctl/grpcvtctldserver/server.go#L2094-L2130","documentation":"Each entry of req.AppCheckedMetrics must be a recognizable metric name (possibly a disaggregated per-item name like 'loadaverage.mysql'). base.DisaggregateMetricName parses the entry into its base metric; if parsing fails, the whole UpdateThrottlerConfig call is rejected.","triggerScenarios":"Passing an entry in AppCheckedMetrics (e.g. --app-checked-metrics flag) that cannot be disaggregated into a known metric — malformed string, wrong separator, or unknown base metric name.","commonSituations":"Comma/space-separated list formatting mistakes on the CLI, entries like 'foo.bar' where 'foo' is not a known metric, or copy-pasted values from docs of a different Vitess version.","solutions":["Validate each app-checked-metric entry against base.DisaggregateMetricName/known metric names and fix the offending entry.","Ensure the per-item suffix syntax (e.g. '.mysql') is supported for the chosen metric.","Remove the invalid entry from AppCheckedMetrics if it is not needed."],"exampleFix":"// before\n--app-checked-metrics \"loadavg.mysql\"\n// after\n--app-checked-metrics \"loadaverage.mysql\"","handlingStrategy":"validation","validationCode":"for _, m := range req.AppCheckedMetrics {\n    if _, _, err := base.DisaggregateMetricName(m); err != nil {\n        return fmt.Errorf(\"bad app-checked-metric %q: %v\", m, err)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Parse metric entries with base.DisaggregateMetricName in the CLI wrapper before sending the RPC","Generate AppCheckedMetrics from config rather than free-form strings","Test metric list parsing in CI"],"tags":["vitess","throttler","validation","grpc"],"backgroundTag":"invalid-config-value","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}