{"record":{"id":"16627de921c306fd","repo":"kubernetes/kops","slug":"unexpected-path-q","errorCode":null,"errorMessage":"unexpected path: %q","messagePattern":"unexpected path: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/commands/toolbox_enroll.go","lineNumber":916,"sourceCode":"\n\t\t\tsrcPath, err := vfsContext.BuildVfsPath(src)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"building vfs path: %w\", err)\n\t\t\t}\n\n\t\t\tsrcFiles, err := srcPath.ReadTree(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"reading tree: %w\", err)\n\t\t\t}\n\t\t\tbasePath := srcPath.Path()\n\t\t\tfor _, srcFile := range srcFiles {\n\t\t\t\tb, err := srcFile.ReadFile(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"reading file: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif !strings.HasPrefix(srcFile.Path(), basePath) {\n\t\t\t\t\treturn fmt.Errorf(\"unexpected path: %q\", srcFile.Path())\n\t\t\t\t}\n\t\t\t\trelativePath := strings.TrimPrefix(srcFile.Path(), basePath)\n\n\t\t\t\tbootstrapData.NodeupScriptAdditionalFiles[path.Join(dest, relativePath)] = b\n\t\t\t}\n\n\t\t\t*pSrc = dest\n\t\t\treturn nil\n\t\t}\n\n\t\tfor i := range nodeupConfig.EtcdManifests {\n\t\t\tif err := remapFile(&nodeupConfig.EtcdManifests[i], path.Join(targetDir)); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\t// The kops-channels static pod is built at cloudup with the remote bootstrap URL baked\n\t\t// into its args. To run on an enrolled node without state-store credentials, copy the","sourceCodeStart":898,"sourceCodeEnd":934,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/commands/toolbox_enroll.go#L898-L934","documentation":"While remapping a remote s3:// tree to a local host directory, kops asserts that every file returned by ReadTree lives under the tree's base path (basePath := srcPath.Path()); relative paths are computed with strings.TrimPrefix. If a listed file's path does not have that prefix, the invariant is broken and this error is thrown instead of writing the file to a bogus local location.","triggerScenarios":"GetBootstrapData -> remapTree on an s3:// addons/keypairs/secrets tree where the vfs VFSPath enumeration yields a path that does not share the srcPath base prefix — typically a backend change/bug in vfs ReadTree path normalization, an unexpected symlink-like or case-differing key, or the tree path being mutated between BuildVfsPath and iteration.","commonSituations":"Using an unusual or customized state-store backend whose object keys don't normalize the same way as vfs's base path; version drift where ReadTree starts returning relative or absolute-normalized keys; running a patched/newer kops against a state store layout the code doesn't expect.","solutions":["Report/capture the offending path printed in the error (%q) and compare it with the ConfigStore.Base value to see how it diverges (trailing slash, case, relative form).","Upgrade (or downgrade) kops to a version where vfs.ReadTree path handling matches your backend; check the vfs S3/GCS implementation for known normalization fixes.","Sanity-check the state store keys (aws s3 ls) for odd characters, leading slashes, or mixed-case segments under the base prefix and normalize them.","If only one backend is affected, switch the state store to a standard layout (e.g. plain s3://bucket/cluster) and re-run enroll."],"exampleFix":"// before: keys uploaded with leading slash break prefix matching\naws s3 cp addons/ s3://bucket//cluster/addons/ --recursive\n// after: upload under the exact base path with no double slashes\naws s3 cp addons/ s3://bucket/cluster/addons/ --recursive","handlingStrategy":"validation","validationCode":"// Before enroll: confirm state-store keys sit under the base prefix with no oddities\naws s3 ls s3://<bucket>/<cluster>/addons/ --recursive | awk '{print $4}' | \\\n  grep -v '^<cluster>/addons/' && echo 'WARNING: keys outside expected base prefix'","typeGuard":"func hasBasePrefix(p, basePath string) bool {\n    return strings.HasPrefix(p, basePath)\n}","tryCatchPattern":"if err := runToolboxEnroll(ctx, ...); err != nil {\n    var unexpected *ErrUnexpectedPath // or match on \"unexpected path:\"\n    if strings.Contains(err.Error(), \"unexpected path:\") {\n        log.Fatalf(\"vfs tree layout invariant broken; inspect the path in: %v\", err)\n    }\n    return err\n}","preventionTips":["Keep the state store managed by kops itself — don't hand-upload objects with different key shapes.","Use a standard s3://bucket/cluster base with no double slashes or mixed case.","Pin the kops CLI version to the cluster's version so vfs ReadTree semantics match what wrote the state."],"tags":["go","vfs","path-prefix","invariant","enrollment"],"backgroundTag":"vfs-path-prefix-mismatch","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}