{"record":{"id":"b0010a8c7f92bfd2","repo":"AlistGo/alist","slug":"invalid-line-s-because-file-info-must-end-with-b0010a","errorCode":null,"errorMessage":"invalid line: %s, because file info must end with ':'","messagePattern":"invalid line: (.+?), because file info must end with ':'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/url_tree/util.go","lineNumber":115,"sourceCode":"// [FileName:][FileSize:][Modified:]Url\nfunc parseFileLine(line string, headSize bool) (*Node, error) {\n\t// if there is no url, it is an error\n\tif !strings.Contains(line, \"http://\") && !strings.Contains(line, \"https://\") {\n\t\treturn nil, fmt.Errorf(\"invalid line: %s, because url is required for file\", line)\n\t}\n\tindex := strings.Index(line, \"http://\")\n\tif index == -1 {\n\t\tindex = strings.Index(line, \"https://\")\n\t}\n\turl := line[index:]\n\tinfo := line[:index]\n\tnode := &Node{\n\t\tUrl: url,\n\t}\n\thaveSize := false\n\tif index > 0 {\n\t\tif !strings.HasSuffix(info, \":\") {\n\t\t\treturn nil, fmt.Errorf(\"invalid line: %s, because file info must end with ':'\", line)\n\t\t}\n\t\tinfo = info[:len(info)-1]\n\t\tif info == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"invalid line: %s, because file name can't be empty\", line)\n\t\t}\n\t\tinfoParts := strings.Split(info, \":\")\n\t\tnode.Name = infoParts[0]\n\t\tif len(infoParts) > 1 {\n\t\t\tsize, err := strconv.ParseInt(infoParts[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid line: %s, because file size must be an integer\", line)\n\t\t\t}\n\t\t\tnode.Size = size\n\t\t\thaveSize = true\n\t\t\tif len(infoParts) > 2 {\n\t\t\t\tmodified, err := strconv.ParseInt(infoParts[2], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"invalid line: %s, because file modified must be an unix timestamp\", line)","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/url_tree/util.go#L97-L133","documentation":"When a url_tree file line has metadata before the URL (index of the URL > 0), that metadata section must terminate with ':' as the separator convention (FileName:FileSize:Modified:Url). If the segment immediately before the URL does not end with ':', the line grammar is violated and parsing stops.","triggerScenarios":"Lines like 'name size https://...' (space separators) or 'name:1024 https://...' — any prefix that does not end with ':' right where the URL begins.","commonSituations":"Writing the structure with spaces instead of colons, or deleting the trailing colon while editing sizes/timestamps. Caught at BuildTree during Init.","solutions":["Format file lines strictly as Name:Size:Modified:URL with colons separating each metadata field.","Omit metadata entirely (bare URL) — the node name then defaults to stdpath.Base(url).","Double-check the last metadata field before the URL still ends with ':'."],"exampleFix":"// before\nmovie.mp4 1024 https://x/m.mp4\n\n// after\nmovie.mp4:1024: https://x/m.mp4","handlingStrategy":"validation","validationCode":"func validateFileLine(line string) error {\n    idx := strings.Index(line, \"http://\")\n    if idx == -1 { idx = strings.Index(line, \"https://\") }\n    if idx <= 0 { return nil } // bare URL or missing URL handled elsewhere\n    if !strings.HasSuffix(line[:idx], \":\") {\n        return fmt.Errorf(\"metadata must end with ':' before URL\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"must end with ':'\") { /* convert space separators to colons in the echoed line */ }","preventionTips":["Use ':' as the only metadata separator","Prefer bare URL lines when no metadata is needed","Lint the structure with a parser before saving"],"tags":["url-tree","parsing","config","validation"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}