{"record":{"id":"048691c71daae8c9","repo":"AlistGo/alist","slug":"invalid-video-path-w","errorCode":null,"errorMessage":"invalid video path: %w","messagePattern":"invalid video path: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"drivers/local/util.go","lineNumber":156,"sourceCode":"\n\t// outputFormat := imaging.PNG\n\t// encodeOptions := []imaging.EncodeOption{}\n\n\terr = imaging.Encode(&buf, thumbImg, outputFormat, encodeOptions...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to encode thumbnail: %w\", err)\n\t}\n\n\tthumbImg = nil\n\n\treturn &buf, nil\n}\n\n// Get the snapshot of the video\nfunc (d *Local) GetSnapshot(videoPath string) (imgData *bytes.Buffer, err error) {\n\tsanitized, err := sanitizeFilePath(videoPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid video path: %w\", err)\n\t}\n\tvideoPath = sanitized\n\n\t// Run ffprobe to get the video duration\n\tjsonOutput, err := ffmpeg.Probe(videoPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// get format.duration from the json string\n\ttype probeFormat struct {\n\t\tDuration string `json:\"duration\"`\n\t}\n\ttype probeData struct {\n\t\tFormat probeFormat `json:\"format\"`\n\t}\n\tvar probe probeData\n\terr = json.Unmarshal([]byte(jsonOutput), &probe)\n\tif err != nil {","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/local/util.go#L138-L174","documentation":"GetSnapshot rejects the video path via the same sanitizeFilePath gate used for images: path must be absolute, free of shell metacharacters (;;&|`$<>!\\n\\r\\x00), stat-able, and a regular file. The wrapped error names the failing rule. This runs before ffprobe, so it fires only on path problems, not on media problems.","triggerScenarios":"Requesting a thumbnail for a video whose path contains '$' or ';' (very common in scene-release filenames), a video behind a broken symlink, or a video that was deleted after the directory listing was cached.","commonSituations":"Filenames like 'Movie.2023.1080p;$hadow.mp4' or subtitled releases with '!' in the name; symlinked media libraries; thumbnails requested for entries from a stale cache.","solutions":["Read the wrapped message to see which rule failed","Rename files containing metacharacters, or adjust sanitizeFilePath since ffmpeg-go spawns ffmpeg directly (no shell) and only NUL/newline truly need rejecting","Verify the video exists and the process user can stat it"],"exampleFix":"// before: every metacharacter rejected, ffmpeg invoked without a shell anyway\nif strings.ContainsAny(cleaned, \";&|`$<>!\\n\\r\\x00\") {\n    return \"\", fmt.Errorf(\"file path contains invalid characters: %s\", path)\n}\n\n// after: only reject characters that cannot appear in a single argv element\nif strings.ContainsAny(cleaned, \"\\n\\r\\x00\") {\n    return \"\", fmt.Errorf(\"file path contains invalid characters: %s\", path)\n}","handlingStrategy":"validation","validationCode":"if !filepath.IsAbs(videoPath) { return nil, fmt.Errorf(\"video path must be absolute\") }\nif info, err := os.Stat(videoPath); err != nil || !info.Mode().IsRegular() { return nil, nil /* skip snapshot */ }","typeGuard":null,"tryCatchPattern":"In getThumb, wrap GetSnapshot; on error return (nil, nil, err-swigged-thumb) so the listing still renders and the failure is only logged.","preventionTips":["Keep video paths absolute from the driver root","Skip snapshots for files whose names contain newline/NUL instead of failing the whole request","Remember sanitizeFilePath rejects many legal filenames ($ ; !) — rename media or narrow the character blocklist"],"tags":["filesystem","path-validation","video-thumbnail","ffmpeg","local-driver"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}