{"record":{"id":"d803e0d8880e1589","repo":"grpc/grpc-go","slug":"xds-field-clientlistenerresourcenametemplate-q-o","errorCode":null,"errorMessage":"xds: field clientListenerResourceNameTemplate %q of authority %q doesn't start with prefix %q","messagePattern":"xds: field clientListenerResourceNameTemplate %q of authority %q doesn't start with prefix %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/bootstrap/bootstrap.go","lineNumber":644,"sourceCode":"\t// Default value of the default client listener name template is \"%s\".\n\tif c.clientDefaultListenerResourceNameTemplate == \"\" {\n\t\tc.clientDefaultListenerResourceNameTemplate = \"%s\"\n\t}\n\tif len(c.xDSServers) == 0 {\n\t\treturn fmt.Errorf(\"xds: required field `xds_servers` not found in bootstrap configuration: %s\", string(data))\n\t}\n\n\t// Post-process the authorities' client listener resource template field:\n\t// - if set, it must start with \"xdstp://<authority_name>/\"\n\t// - if not set, it defaults to \"xdstp://<authority_name>/envoy.config.listener.v3.Listener/%s\"\n\tfor name, authority := range c.authorities {\n\t\tprefix := fmt.Sprintf(\"xdstp://%s\", url.PathEscape(name))\n\t\tif authority.ClientListenerResourceNameTemplate == \"\" {\n\t\t\tauthority.ClientListenerResourceNameTemplate = prefix + \"/envoy.config.listener.v3.Listener/%s\"\n\t\t\tcontinue\n\t\t}\n\t\tif !strings.HasPrefix(authority.ClientListenerResourceNameTemplate, prefix) {\n\t\t\treturn fmt.Errorf(\"xds: field clientListenerResourceNameTemplate %q of authority %q doesn't start with prefix %q\", authority.ClientListenerResourceNameTemplate, name, prefix)\n\t\t}\n\t}\n\treturn nil\n}\n\n// GetConfiguration returns the bootstrap configuration initialized by reading\n// the bootstrap file found at ${GRPC_XDS_BOOTSTRAP} or bootstrap contents\n// specified at ${GRPC_XDS_BOOTSTRAP_CONFIG}. If both env vars are set, the\n// former is preferred.\n//\n// This function tries to process as much of the bootstrap file as possible (in\n// the presence of the errors) and may return a Config object with certain\n// fields left unspecified, in which case the caller should use some sane\n// defaults.\n//\n// This function returns an error if it's unable to parse the contents of the\n// bootstrap config. It returns (nil, nil) if none of the env vars are set.\nfunc GetConfiguration() (*Config, error) {","sourceCodeStart":626,"sourceCodeEnd":662,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/bootstrap/bootstrap.go#L626-L662","documentation":"Returned by Config.UnmarshalJSON when an authority's client_listener_resource_name_template, if set, does not start with the required prefix 'xdstp://<authority_name>/'. The prefix is derived from the authority's map key, URL-path-escaped.","triggerScenarios":"Triggered at bootstrap.go:644 when authority.ClientListenerResourceNameTemplate is non-empty and does not have the prefix strings.HasPrefix(template, 'xdstp://<name>/').","commonSituations":"Template copied from another authority without updating the prefix to match the new authority key; template uses an old-style (non-xdstp) name; authority key renamed but template not updated; special characters in the authority name not path-escaped consistently.","solutions":["Either remove the client_listener_resource_name_template field (it defaults to 'xdstp://<authority_name>/envoy.config.listener.v3.Listener/%s') or set it to start with 'xdstp://<authority_name>/'.","Match the authority key exactly in the prefix, including URL path-escaping for special characters.","Keep the '%s' substitution token so the service authority can be injected.","Use the same spelling/casing for the authority key and the prefix."],"exampleFix":"// before (key 'auth1' but template uses 'auth2')\n\"authorities\":{\"auth1\":{\"client_listener_resource_name_template\":\"xdstp://auth2/envoy.config.listener.v3.Listener/%s\"}}\n\n// after\n\"authorities\":{\"auth1\":{\"client_listener_resource_name_template\":\"xdstp://auth1/envoy.config.listener.v3.Listener/%s\"}}","handlingStrategy":"validation","validationCode":"// For each authority, confirm its template prefix matches its key.\nfunc validateAuthorityPrefixes(auths map[string]map[string]string) error {\n    for name, a := range auths {\n        tmpl := a[\"client_listener_resource_name_template\"]\n        if tmpl == \"\" {\n            continue // default is fine\n        }\n        want := \"xdstp://\" + url.PathEscape(name) + \"/\"\n        if !strings.HasPrefix(tmpl, want) {\n            return fmt.Errorf(\"authority %q template must start with %q\", name, want)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := bootstrap.NewConfigFromContents(data); err != nil {\n    if strings.Contains(err.Error(), \"clientListenerResourceNameTemplate\") {\n        // align the authority template prefix with the authority key.\n    }\n}","preventionTips":["Omit client_listener_resource_name_template to take the safe default.","When renaming an authority key, update every template prefix.","URL-path-escape the authority name in the prefix."],"tags":["grpc","xds","bootstrap","authority","xdstp","config","go"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}