{"record":{"id":"846b9aa6dcf76b6b","repo":"apache/beam","slug":"namespace-and-name-are-required-to-be-non-empty-got-q-and-q","errorCode":null,"errorMessage":"namespace and name are required to be non-empty, got %q and %q","messagePattern":"namespace and name are required to be non-empty, got %q and %q","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/metrics/metrics.go","lineNumber":245,"sourceCode":"\tcase kindDoFnMsec:\n\t\treturn \"DoFnMsec\"\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"Unknown metric type value: %v\", uint8(t)))\n\t}\n}\n\n// name is a pair of strings identifying a specific metric.\ntype name struct {\n\tnamespace, name string\n}\n\nfunc (n name) String() string {\n\treturn fmt.Sprintf(\"%s.%s\", n.namespace, n.name)\n}\n\nfunc newName(ns, n string) name {\n\tif len(n) == 0 || len(ns) == 0 {\n\t\tpanic(fmt.Sprintf(\"namespace and name are required to be non-empty, got %q and %q\", ns, n))\n\t}\n\treturn name{namespace: ns, name: n}\n}\n\n// We hash the name to a uint64 so we avoid using go's native string hashing for\n// every use of a metrics. uint64s have faster lookup than strings as a result.\n// Collisions are possible, but statistically unlikely as namespaces and names\n// are usually short enough to avoid this. A sync.Pool is used  because it can provide\n// goroutine-local values that reduce contention and profiling shows hashName from NewCounter\n// can be a contention hotspot. See parallel benches metrics_test.go:BenchmarkMetrics/*\nvar (\n\thashPool = sync.Pool{\n\t\tNew: func() interface{} {\n\t\t\treturn fnv.New64a()\n\t\t},\n\t}\n)\n","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/metrics/metrics.go#L227-L263","documentation":"newName constructs the namespace/name key for a Beam user metric (counter, distribution, gauge). Both parts must be non-empty; otherwise the metric key would be malformed or collide, so newName panics. It is invoked by NewCounter, NewDistribution, and NewGauge.","triggerScenarios":"Calling metrics.NewCounter(ns, \"\"), NewCounter(\"\", name), or any of the metric constructors with an empty namespace or empty name string.","commonSituations":"Metric names pulled from constants/config/env where a variable is empty (missing env var, empty config field, typo'd constant), or building names dynamically with fmt.Sprintf that produced an empty component.","solutions":["Pass a non-empty namespace and a non-empty metric name to the metric constructor.","Validate/trim the inputs before constructing the metric and fail early with a clear message.","Fix the source of the empty string (missing config key, unset env var, wrong constant)."],"exampleFix":"// before\nc := metrics.NewCounter(appNs, metricName) // panics if either is \"\"\n// after\nif appNs == \"\" || metricName == \"\" {\n\tlog.Fatalf(\"metric namespace and name must be non-empty: ns=%q name=%q\", appNs, metricName)\n}\nc := metrics.NewCounter(appNs, metricName)","handlingStrategy":"validation","validationCode":"if ns == \"\" || name == \"\" {\n\treturn fmt.Errorf(\"metric ns=%q name=%q must be non-empty\", ns, name)\n}\nc := metrics.NewCounter(ns, name)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Define metric names/namespace as package-level constants, never from possibly-empty runtime strings.","Trim and validate names sourced from config or environment at startup.","Add a startup check that all declared metric names are non-empty."],"tags":["go","panic","beam","metrics","validation"],"backgroundTag":"empty-required-field","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}