{"record":{"id":"0f8e94d1202a05b4","repo":"grpc/grpc-go","slug":"must-come-in-between-service-and-method-only-on","errorCode":null,"errorMessage":"/ must come in between service and method, only one /","messagePattern":"/ must come in between service and method, only one /","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gcp/observability/config.go","lineNumber":65,"sourceCode":"\t\treturn \"\"\n\t}\n\tif credentials.ProjectID == \"\" {\n\t\tlogger.Infof(\"Failed to find project ID in default credential: %v\", err)\n\t\treturn \"\"\n\t}\n\tlogger.Infof(\"Found project ID from Google Default Credential: %v\", credentials.ProjectID)\n\treturn credentials.ProjectID\n}\n\n// validateMethodString validates whether the string passed in is a valid\n// pattern.\nfunc validateMethodString(method string) error {\n\tif strings.HasPrefix(method, \"/\") {\n\t\treturn errors.New(\"cannot have a leading slash\")\n\t}\n\tserviceMethod := strings.Split(method, \"/\")\n\tif len(serviceMethod) != 2 {\n\t\treturn errors.New(\"/ must come in between service and method, only one /\")\n\t}\n\tif serviceMethod[1] == \"\" {\n\t\treturn errors.New(\"method name must be non empty\")\n\t}\n\tif serviceMethod[0] == \"*\" {\n\t\treturn errors.New(\"cannot have service wildcard * i.e. (*/m)\")\n\t}\n\treturn nil\n}\n\nfunc validateLogEventMethod(methods []string, exclude bool) error {\n\tfor _, method := range methods {\n\t\tif method == \"*\" {\n\t\t\tif exclude {\n\t\t\t\treturn errors.New(\"cannot have exclude and a '*' wildcard\")\n\t\t\t}\n\t\t\tcontinue\n\t\t}","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/gcp/observability/config.go#L47-L83","documentation":"Returned by validateMethodString (gcp/observability/config.go:65) when strings.Split(method, \"/\") does not yield exactly two parts. This means there is either no '/' at all, or more than one '/' (e.g. 'foo', 'a/b/c'). The observability config requires exactly one '/' separating the fully-qualified service name from the method name.","triggerScenarios":"A methods entry that is a bare service name with no method (foo.Bar), a bare method (Bar), an empty string, or contains multiple slashes (a/b/c, foo.Bar/Baz/extra). Reached while parsing the observability config.","commonSituations":"Typing only the service name; using a path-like method string; concatenating package + service + method with extra slashes; trailing slash (foo.Bar/Baz/).","solutions":["Ensure each method entry has exactly one '/' between service and method: <package>.<Service>/<Method>.","Strip accidental trailing slashes and avoid extra path segments.","Lint the methods list before deploying the config."],"exampleFix":"// before\n{\"methods\":[\"foo.Bar\"]}        // no '/'\n{\"methods\":[\"foo.Bar/Baz/extra\"]} // too many '/'\n\n// after\n{\"methods\":[\"foo.Bar/Baz\"]}","handlingStrategy":"validation","validationCode":"parts := strings.Split(method, \"/\")\nif len(parts) != 2 || parts[0] == \"\" {\n    return fmt.Errorf(\"method %q must be <service>/<method> with exactly one '/'\", method)\n}","typeGuard":null,"tryCatchPattern":"if _, err := unmarshalAndVerifyConfig(raw); err != nil { log.Fatalf(\"config: %v\", err) }","preventionTips":["Use a config schema/validator (e.g. JSON schema) that enforces the single-slash shape."],"tags":["go","grpc","observability","config-validation","logging"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}