{"record":{"id":"9cfbbc9443fc3950","repo":"jaegertracing/jaeger","slug":"field-s-is-missing-a-tag-metric","errorCode":null,"errorMessage":"Field %s is missing a tag 'metric'","messagePattern":"Field (.+?) is missing a tag 'metric'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/metrics/metrics.go","lineNumber":55,"sourceCode":"\t\tfactory = NullFactory\n\t}\n\n\tcounterPtrType := reflect.TypeFor[Counter]()\n\tgaugePtrType := reflect.TypeFor[Gauge]()\n\ttimerPtrType := reflect.TypeFor[Timer]()\n\thistogramPtrType := reflect.TypeFor[Histogram]()\n\n\tv := reflect.ValueOf(m).Elem()\n\tt := v.Type()\n\tfor i := 0; i < t.NumField(); i++ {\n\t\ttags := make(map[string]string)\n\t\tmaps.Copy(tags, globalTags)\n\t\tvar histogramBuckets []float64\n\t\tvar timerBuckets []time.Duration\n\t\tfield := t.Field(i)\n\t\tmetric := field.Tag.Get(\"metric\")\n\t\tif metric == \"\" {\n\t\t\treturn fmt.Errorf(\"Field %s is missing a tag 'metric'\", field.Name)\n\t\t}\n\t\tif tagString := field.Tag.Get(\"tags\"); tagString != \"\" {\n\t\t\tfor tagPair := range strings.SplitSeq(tagString, \",\") {\n\t\t\t\ttag := strings.Split(tagPair, \"=\")\n\t\t\t\tif len(tag) != 2 {\n\t\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\t\"Field [%s]: Tag [%s] is not of the form key=value in 'tags' string [%s]\",\n\t\t\t\t\t\tfield.Name, tagPair, tagString,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\ttags[tag[0]] = tag[1]\n\t\t\t}\n\t\t}\n\t\tif bucketString := field.Tag.Get(\"buckets\"); bucketString != \"\" {\n\t\t\tswitch {\n\t\t\tcase field.Type.AssignableTo(timerPtrType):\n\t\t\t\tbucketValues := strings.Split(bucketString, \",\")\n\t\t\t\tfor _, bucket := range bucketValues {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/jaegertracing/jaeger/blob/806f4447841ecdb60519f408b004a599d515f437/internal/metrics/metrics.go#L37-L73","documentation":"metrics.Init() uses reflection over a struct of metric fields and requires every field to carry a `metric:\"name\"` struct tag identifying it. A field whose metric tag is empty/missing is rejected rather than silently skipped, so the metrics struct is fully defined. This keeps metric registration explicit and prevents unregistered zero-value fields.","triggerScenarios":"Calling Init/MustInit/NewTable/buildQueryMetrics on a metrics struct where some exported *Timer/*Gauge/*Counter field lacks the `metric` tag entirely or has an empty `metric:\"\"` value.","commonSituations":"Adding a new field to a metrics struct and forgetting the tag; copy-pasting a field declaration without its tag line; running gofmt/tooling that dropped a malformed tag.","solutions":["Add a `metric:\"<name>\"` tag to the offending field","Check for a typo like `metirc:` in the tag key","Ensure the tag is on the same line as the field, in backticks","Re-run Init; the error names the exact field, so go straight to it"],"exampleFix":"// before\nLatency *Timer\n// after\nLatency *Timer `metric:\"latency\" help:\"request latency\"`","handlingStrategy":"validation","validationCode":"func checkMetricTags(s any) error {\n    t := reflect.TypeOf(s)\n    for i := 0; i < t.NumField(); i++ {\n        if t.Field(i).Tag.Get(\"metric\") == \"\" {\n            return fmt.Errorf(\"field %s missing metric tag\", t.Field(i).Name)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := metrics.Init(&m); err != nil {\n    if strings.Contains(err.Error(), \"missing a tag 'metric'\") {\n        // fix the named field's struct tag\n    }\n    return err\n}","preventionTips":["Always give every metrics-struct field a metric tag when adding it","Copy the whole field line (including backtick tags) when duplicating fields","Add a unit test that Initializes all metrics structs","Avoid hand-editing struct tags without running go vet"],"tags":["reflection","struct-tags","metrics"],"backgroundTag":"missing-struct-tag","analyzedSha":"806f4447841ecdb60519f408b004a599d515f437","analyzedAt":"2026-09-01T02:39:22.140Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}