{"record":{"id":"82c8ba43fa1a4603","repo":"AlistGo/alist","slug":"tool-s-not-found","errorCode":null,"errorMessage":"tool %s not found","messagePattern":"tool (.+?) not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/offline_download/tool/tools.go","lineNumber":19,"sourceCode":"package tool\n\nimport (\n\t\"fmt\"\n\t\"github.com/alist-org/alist/v3/internal/model\"\n\t\"sort\"\n)\n\nvar (\n\tTools = make(ToolsManager)\n)\n\ntype ToolsManager map[string]Tool\n\nfunc (t ToolsManager) Get(name string) (Tool, error) {\n\tif tool, ok := t[name]; ok {\n\t\treturn tool, nil\n\t}\n\treturn nil, fmt.Errorf(\"tool %s not found\", name)\n}\n\nfunc (t ToolsManager) Add(tool Tool) {\n\tt[tool.Name()] = tool\n}\n\nfunc (t ToolsManager) Names() []string {\n\tnames := make([]string, 0, len(t))\n\tfor name := range t {\n\t\tif tool, err := t.Get(name); err == nil && tool.IsReady() {\n\t\t\tnames = append(names, name)\n\t\t}\n\t}\n\tsort.Strings(names)\n\treturn names\n}\n\nfunc (t ToolsManager) Items() []model.SettingItem {","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/offline_download/tool/tools.go#L1-L37","documentation":"ToolsManager.Get() looks up an offline-download tool by name in a registry populated by each package's init() (115, 123_open, guangyapan, http, pikpak, thunder, transmission, aria2/qbit via their own registrations). An unknown name — before any availability check like IsReady — returns this error. It almost always means the requested tool name does not match a registered tool.","triggerScenarios":"Passing a 'tool' field in the offline download API that is not a registered name: misspellings ('picpak'), wrong casing ('Thunder' vs 'thunder'), or a tool package excluded from the build.","commonSituations":"Typos in API clients or scripts; using the tool's display name instead of its registered Name(); forks that compile out driver packages (some drivers are behind build tags or split binaries).","solutions":["List valid names via tool.Tools.Names() (or the API endpoint that exposes them) and use an exact match","Correct spelling/casing of the tool name in the request","If a driver is missing, build the binary with that driver package included / use the full build"],"exampleFix":"// before\nname := \"picpak\"\ntool, err := tool.Tools.Get(name)\n\n// after\nname := \"pikpak\"\nif _, err := tool.Tools.Get(name); err != nil {\n    log.Fatalf(\"unknown tool %q, available: %v\", name, tool.Tools.Names())\n}","handlingStrategy":"validation","validationCode":"names := tool.Tools.Names() // only ready tools\nif !slices.Contains(names, name) {\n    return fmt.Errorf(\"tool %q not found; available: %v\", name, names)\n}\nt, err := tool.Tools.Get(name)","typeGuard":"func isValidToolName(name string) bool {\n    _, ok := tool.Tools[name]\n    return ok\n}","tryCatchPattern":"t, err := tool.Tools.Get(name)\nif err != nil {\n    return fmt.Errorf(\"%w (available: %v)\", err, tool.Tools.Names())\n}","preventionTips":["Always source tool names from tool.Tools.Names(), never hardcode them","Treat tool names as case-sensitive identifiers, not display labels","Validate the name at the API boundary before touching the registry"],"tags":["tool-registry","lookup","offline-download","configuration"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}