{"record":{"id":"ada77730315014b8","repo":"AlistGo/alist","slug":"file-share-does-not-support-nested-path","errorCode":null,"errorMessage":"file share does not support nested path","messagePattern":"file share does not support nested path","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"server/handles/share.go","lineNumber":363,"sourceCode":"\tif token == \"\" {\n\t\tcommon.ErrorStrResp(c, \"share password required\", 401)\n\t\treturn false\n\t}\n\tif err := shareauth.VerifyAccess(share, token); err != nil {\n\t\tcommon.ErrorResp(c, err, 401)\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc shouldTrackShareContentAccess(c *gin.Context) bool {\n\treturn c.Request.Method != http.MethodHead\n}\n\nfunc resolveShareTarget(share *model.Share, rawRelPath string) (string, string, error) {\n\tcleanRelPath := utils.FixAndCleanPath(rawRelPath)\n\tif !share.IsDir && cleanRelPath != \"/\" {\n\t\treturn \"\", \"\", fmt.Errorf(\"file share does not support nested path\")\n\t}\n\tif cleanRelPath == \"/\" {\n\t\treturn share.RootPath, \"/\", nil\n\t}\n\ttarget := utils.FixAndCleanPath(stdpath.Join(share.RootPath, cleanRelPath))\n\tif !utils.IsSubPath(share.RootPath, target) {\n\t\treturn \"\", \"\", fmt.Errorf(\"share path out of range\")\n\t}\n\treturn target, cleanRelPath, nil\n}\n\nfunc resolveShareWildcardTarget(share *model.Share, rawPath string) (string, string, error) {\n\tpath, err := url.PathUnescape(rawPath)\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\treturn resolveShareTarget(share, strings.TrimPrefix(path, \"/\"))\n}","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/server/handles/share.go#L345-L381","documentation":"Returned by resolveShareTarget (server/handles/share.go:363) when a share whose target is a single file (share.IsDir == false) is requested with any relative path other than \"/\". A file share exposes exactly one resource — its root — so nested sub-paths have no meaning and are rejected before any filesystem access.","triggerScenarios":"GET on a file share's content endpoint with a URL like /s/<shareID>/extra/segment or a wildcard path resolving below the file; clients that build share URLs by appending a filename to the share root.","commonSituations":"Generic download helpers that always append a filename to a base URL; resuming tools that reconstruct paths; sharing a file when the client assumed a directory share.","solutions":["Request the share root only (relative path \"/\") for file shares","If nested paths must work, share the parent directory instead of the single file","Branch client logic on the share's is_dir flag before building the path"],"exampleFix":"// before\nurl := fmt.Sprintf(\"/s/%s/report.pdf\", shareID) // file share\n// after\nurl := fmt.Sprintf(\"/s/%s\", shareID) // file share serves its root","handlingStrategy":"validation","validationCode":"func sharePathAllowed(isDir bool, relPath string) bool {\n  cleaned := path.Clean(\"/\" + relPath)\n  return isDir || cleaned == \"/\"\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Branch URL construction on the share's is_dir flag","Never append filenames to single-file share URLs","Share the parent directory when nested access is needed"],"tags":["share","path-resolution","validation"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}