{"record":{"id":"153dd73e678c6055","repo":"containerd/containerd","slug":"root-path-is-required","errorCode":null,"errorMessage":"root_path is required","messagePattern":"root_path is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/snapshots/devmapper/config.go","lineNumber":108,"sourceCode":"\n\tif c.FileSystemType == \"\" {\n\t\tc.FileSystemType = fsTypeExt4\n\t}\n\n\tc.BaseImageSizeBytes = uint64(baseImageSize)\n\treturn nil\n}\n\n// Validate makes sure configuration fields are valid\nfunc (c *Config) Validate() error {\n\tvar result []error\n\n\tif c.PoolName == \"\" {\n\t\tresult = append(result, fmt.Errorf(\"pool_name is required\"))\n\t}\n\n\tif c.RootPath == \"\" {\n\t\tresult = append(result, fmt.Errorf(\"root_path is required\"))\n\t}\n\n\tif c.BaseImageSize == \"\" {\n\t\tresult = append(result, fmt.Errorf(\"base_image_size is required\"))\n\t}\n\n\tif c.FileSystemType != \"\" {\n\t\tswitch c.FileSystemType {\n\t\tcase fsTypeExt4, fsTypeXFS, fsTypeExt2:\n\t\tdefault:\n\t\t\tresult = append(result, fmt.Errorf(\"unsupported Filesystem Type: %q\", c.FileSystemType))\n\t\t}\n\t} else {\n\t\tresult = append(result, fmt.Errorf(\"filesystem type cannot be empty\"))\n\t}\n\n\treturn errors.Join(result...)\n}","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/containerd/containerd/blob/4246446a2bf7d03837b0244118d858799393bd80/plugins/snapshots/devmapper/config.go#L90-L126","documentation":"Validate() in the devmapper snapshotter config collects all missing/invalid field errors and joins them. This error means the RequiredDevicePathRoot 'root_path' field was left empty in the plugin configuration. The library refuses to build a snapshotter without knowing where device-mapper state should live.","triggerScenarios":"Calling LoadConfig or NewSnapshotter with a config struct whose RootPath field is the empty string; also surfaced by TestFieldValidation/TestExistingPoolFieldValidation when exercising Validate with unset fields.","commonSituations":"Operators omit root_path in the plugin config JSON, env-var/flag mapping silently fails to populate RootPath, or code constructs config.Config{} programmatically and forgets to set RootPath.","solutions":["Set root_path in the devmapper plugin configuration (e.g. /var/lib/containerd/devmapper) before loading.","Verify the config file/env mapping actually populates RootPath (check key spelling root_path).","Run LoadConfig/Validate early at startup so the missing field fails fast with the joined error list.","Constructing configs in Go: set RootPath explicitly instead of relying on zero values."],"exampleFix":"// before\n{\"plugin\":{\"config\":{\"pool_name\":\"containerd-pool\"}}}\n// after\n{\"plugin\":{\"config\":{\"pool_name\":\"containerd-pool\",\"root_path\":\"/var/lib/containerd/devmapper\"}}}","handlingStrategy":"validation","validationCode":"func validateRootPath(cfg Config) error {\n    if cfg.RootPath == \"\" {\n        return errors.New(\"config: root_path must be set (e.g. /var/lib/containerd/devmapper)\")\n    }\n    if err := os.MkdirAll(cfg.RootPath, 0o700); err != nil {\n        return fmt.Errorf(\"root_path not usable: %w\", err)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"cfg, err := LoadConfig()\nvar cfgErr *ConfigError\nif errors.As(err, &cfgErr) { /* inspect joined field errors for root_path */ }","preventionTips":["Include root_path in every devmapper config template","Fail fast by calling Validate in startup code before using the snapshotter","Add a unit test asserting LoadConfig rejects empty root_path","Log the full joined Validate() error, not just the first line"],"tags":["devmapper","config","validation","missing-field"],"backgroundTag":"missing-config-field","analyzedSha":"4246446a2bf7d03837b0244118d858799393bd80","analyzedAt":"2026-09-02T00:14:43.053Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}