{"record":{"id":"86497276f9d3d88e","repo":"argoproj/argo-workflows","slug":"metric-name-is-invalid-names-may-only-contain-alp","errorCode":null,"errorMessage":"metric name is invalid: names may only contain alphanumeric characters or '_'","messagePattern":"metric name is invalid: names may only contain alphanumeric characters or '_'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/metrics/metrics_custom.go","lineNumber":213,"sourceCode":"\t}\n\terr = m.createCustomMetric(metricSpec)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tm.attachCustomMetricToWorkflow(metricSpec, ownerKey)\n\tinst := m.GetInstrument(metricSpec.Name)\n\tif inst == nil {\n\t\treturn nil, fmt.Errorf(\"failed to create new metric %s\", metricSpec.Name)\n\t}\n\tif customUserData(inst, false) == nil {\n\t\tinst.SetUserdata(newUserData())\n\t}\n\treturn inst, nil\n}\n\nfunc (m *Metrics) UpsertCustomMetric(ctx context.Context, metricSpec *wfv1.Prometheus, ownerKey string, valueFunc RealTimeValueFunc) error {\n\tif !IsValidMetricName(metricSpec.Name) {\n\t\treturn fmt.Errorf(\"%s\", invalidMetricNameError)\n\t}\n\tbaseMetric, err := m.ensureBaseMetric(metricSpec, ownerKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\tmetricValue := getOrCreateValue(baseMetric, metricSpec.GetKey(), metricSpec.Labels)\n\tmetricValue.mutex.Lock()\n\tdefer metricValue.mutex.Unlock()\n\tmetricValue.lastUpdated = time.Now()\n\n\tmetricType := metricSpec.GetMetricType()\n\tswitch {\n\tcase metricSpec.IsRealtime():\n\t\tmetricValue.rtValueFunc = valueFunc\n\n\tcase metricType == wfv1.MetricTypeGauge:\n\t\tval, err := strconv.ParseFloat(metricSpec.Gauge.Value, 64)\n\t\tif err != nil {","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/metrics/metrics_custom.go#L195-L231","documentation":"UpsertCustomMetric validates every custom metric name with IsValidMetricName, which applies Prometheus legacy name rules (alphanumerics and '_', no leading digits issues, and ':' explicitly disallowed). Names with hyphens, dots, spaces, or other characters are rejected before any instrument is created.","triggerScenarios":"Calling UpsertCustomMetric (or submitting a workflow whose metrics section contains a name failing model.LegacyValidation.IsValidMetricName or containing ':') — e.g. name: my-metric or my.metric.","commonSituations":"Users porting names from other monitoring systems that allow hyphens/dots; auto-generated names derived from pod/step labels containing dashes; typos like colons copied from PromQL recording-rule names.","solutions":["Rename the metric to contain only [a-zA-Z0-9_] characters (Prometheus legacy rules)","Replace hyphens/dots with underscores, e.g. my-metric -> my_metric","Remove any ':' characters from the name","Run workflow validation (argo lint) before submitting to catch the name early"],"exampleFix":"// before\nmetrics:\n  - name: my-metric.duration\n    gauge: {value: \"1\"}\n// after\nmetrics:\n  - name: my_metric_duration\n    gauge: {value: \"1\"}","handlingStrategy":"validation","validationCode":"// reuse the library's own check before submitting\nif !metrics.IsValidMetricName(name) {\n\treturn fmt.Errorf(\"metric name %q must match [a-zA-Z0-9_] and contain no ':'\", name)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run argo lint in CI on every workflow/template","Use only underscores as separators in metric names","Never copy names with hyphens/dots/colons from other systems","Validate generated names (e.g. derived from labels) programmatically before submit"],"tags":["metrics","validation","naming","prometheus"],"backgroundTag":"invalid-metric-name","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}