{"record":{"id":"0f2dfc1a375606ca","repo":"go-kratos/kratos","slug":"path-invalid-0f2dfc","errorCode":null,"errorMessage":"path invalid","messagePattern":"path invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"contrib/config/etcd/config.go","lineNumber":61,"sourceCode":"\ntype source struct {\n\tclient  *clientv3.Client\n\toptions *options\n}\n\nfunc New(client *clientv3.Client, opts ...Option) (config.Source, error) {\n\toptions := &options{\n\t\tctx:    context.Background(),\n\t\tpath:   \"\",\n\t\tprefix: false,\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(options)\n\t}\n\n\tif options.path == \"\" {\n\t\treturn nil, errors.New(\"path invalid\")\n\t}\n\n\treturn &source{\n\t\tclient:  client,\n\t\toptions: options,\n\t}, nil\n}\n\n// Load return the config values\nfunc (s *source) Load() ([]*config.KeyValue, error) {\n\tvar opts []clientv3.OpOption\n\tif s.options.prefix {\n\t\topts = append(opts, clientv3.WithPrefix())\n\t}\n\n\trsp, err := s.client.Get(s.options.ctx, s.options.path, opts...)\n\tif err != nil {\n\t\treturn nil, err","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/go-kratos/kratos/blob/668db92c2c001e9552594ba5a8aede8456af6d7e/contrib/config/etcd/config.go#L43-L79","documentation":"Returned by etcd.New in the etcd config source (contrib/config/etcd/config.go:61). The constructor defaults path:\"\" and requires the WithPath option; without it there is no key prefix to query, so New fails immediately. Identical shape to the consul source's path validation - a constructor-time guard, unrelated to etcd connectivity.","triggerScenarios":"Calling etcd.New(clientv3Client) with no options, or with only WithContext/WithPrefix but no etcd.WithPath. Any call where options.path remains \"\" returns this error before any etcd RPC is made.","commonSituations":"Example snippets that show only client creation; enabling prefix mode via etcd.WithPrefix(true) but forgetting the base path it prefixes; refactor dropping the option during migration from another config source.","solutions":["Pass etcd.WithPath with the key prefix holding your config, e.g. etcd.New(client, etcd.WithPath(\"/kratos/app/config\"))","If using WithPrefix(true), remember path is still required as the prefix root","Verify keys exist: etcdctl get --prefix /kratos/app/config"],"exampleFix":"// before\nsrc, err := etcd.New(client)\n// err = path invalid\n\n// after\nsrc, err := etcd.New(client, etcd.WithPath(\"/kratos/app/config\"))","handlingStrategy":"validation","validationCode":"if path == \"\" {\n    return fmt.Errorf(\"etcd config source requires a key prefix\")\n}\nsrc, err := etcd.New(client, etcd.WithPath(path), etcd.WithPrefix(true))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat etcd.WithPath as required; WithPrefix never substitutes for it","Centralize source construction in one config package per app","Assert in tests that New(client, prodOpts...) returns nil error"],"tags":["config","etcd","constructor-validation"],"backgroundTag":null,"analyzedSha":"668db92c2c001e9552594ba5a8aede8456af6d7e","analyzedAt":"2026-08-16T02:07:20.704Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}