{"record":{"id":"f55455161cd34abb","repo":"larksuite/cli","slug":"path-must-not-be-drive-relative-give-a-full-path","errorCode":null,"errorMessage":"path must not be drive-relative; give a full path or a path without a drive letter","messagePattern":"path must not be drive-relative; give a full path or a path without a drive letter","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/vfs/localfileio/path_local_windows.go","lineNumber":29,"sourceCode":"\t\"strings\"\n)\n\n// validatePathPlatform rejects Windows path shapes the policy cannot reason\n// about: network/device namespaces (UNC, \\\\?\\) and NTFS alternate data\n// streams (a colon anywhere past the drive letter would address a hidden\n// stream on an otherwise-allowed file).\nfunc validatePathPlatform(path string) error {\n\tif isWindowsNonLocalNamespace(path) {\n\t\treturn fmt.Errorf(\"path must not use a Windows network or device namespace\")\n\t}\n\tcleaned := filepath.Clean(path)\n\t// A drive-relative path (\"C:foo\") carries a volume but is not absolute: it\n\t// resolves against that drive's own current directory, so the location it\n\t// names is not the one this validation can see. It is also how the stream\n\t// check below would be slipped, since \"C:\" is stripped as the volume and\n\t// the remaining \"foo\" holds no colon.\n\tif filepath.VolumeName(cleaned) != \"\" && !filepath.IsAbs(cleaned) {\n\t\treturn fmt.Errorf(\"path must not be drive-relative; give a full path or a path without a drive letter\")\n\t}\n\tif strings.Contains(cleaned[len(filepath.VolumeName(cleaned)):], \":\") {\n\t\treturn fmt.Errorf(\"path must not address an NTFS alternate data stream\")\n\t}\n\treturn nil\n}\n\nfunc validateLocalInputPlatform(path string) error {\n\tif isWindowsNonLocalNamespace(path) {\n\t\treturn fmt.Errorf(\"local input path must not use a Windows network or device namespace\")\n\t}\n\n\tcleaned := filepath.Clean(path)\n\tvolume := filepath.VolumeName(cleaned)\n\tremainder := strings.TrimLeft(cleaned[len(volume):], `\\/`)\n\tfor _, component := range strings.FieldsFunc(remainder, func(r rune) bool {\n\t\treturn r == '\\\\' || r == '/'\n\t}) {","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/vfs/localfileio/path_local_windows.go#L11-L47","documentation":"On Windows, `validatePathPlatform` rejects drive-relative paths like `C:foo` — a path with a volume but no root slash. Such a path resolves against that drive's own per-drive current directory, so the validated location would differ from the one the OS opens; it would also slip past the NTFS alternate-data-stream colon check. The error is wrapped with the flag name by safePath.","triggerScenarios":"Passing `--file C:report.pdf` or `--output D:data\\out.bin` on Windows (drive letter immediately followed by a non-separator). Note `C:\\abs\\path` and plain `relative\\path` are fine.","commonSituations":"Scripts that string-concatenate a drive letter with a path missing the separator (`drive + ':' + path`); paths captured from tools that report drive-relative locations; per-drive working directories left over from `cd D:` in cmd.exe.","solutions":["Insert the root separator: change `C:foo` to `C:\\foo`.","Drop the drive letter and use a normal relative path resolved against the current directory.","Rebuild the path programmatically with filepath.Join (or filepath.Abs) instead of string concatenation."],"exampleFix":"// before\np := \"C:\" + \"data\\\\out.bin\"        // C:data\\out.bin\n// after\np := filepath.Join(\"C:\\\\\", \"data\", \"out.bin\")  // C:\\data\\out.bin","handlingStrategy":"validation","validationCode":"// Go: normalize drive-relative paths to full paths\nif vol := filepath.VolumeName(p); vol != \"\" && !filepath.IsAbs(p) {\n    p = vol + \"\\\\\" + strings.TrimPrefix(p, vol)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build Windows paths with filepath.Join rather than string concatenation.","After `cd D:` in cmd.exe, remember the prompt directory is per-drive; always pass rooted paths to scripts.","Run filepath.Abs (or an equivalent) on user-supplied Windows paths before storing them in configs."],"tags":["windows","drive-relative-path","path-validation","go"],"backgroundTag":"drive-relative-path-rejected","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}