{"record":{"id":"b7cc9942cef8cf8f","repo":"AlistGo/alist","slug":"mode-error","errorCode":null,"errorMessage":"mode error","messagePattern":"mode error","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/ipfs_api/driver.go","lineNumber":64,"sourceCode":"\tcid := dir.GetID()\n\tif cid != \"\" {\n\t\tipfsPath = path.Join(\"/ipfs\", cid)\n\t} else {\n\t\t// 可能出现ipns dns解析失败的情况，需要重复获取cid，其他情况应该不会出错\n\t\tipfsPath = dir.GetPath()\n\t\tswitch d.Mode {\n\t\tcase \"ipfs\":\n\t\t\tipfsPath = path.Join(\"/ipfs\", ipfsPath)\n\t\tcase \"ipns\":\n\t\t\tipfsPath = path.Join(\"/ipns\", ipfsPath)\n\t\tcase \"mfs\":\n\t\t\tfileStat, err := d.sh.FilesStat(ctx, ipfsPath)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tipfsPath = path.Join(\"/ipfs\", fileStat.Hash)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"mode error\")\n\t\t}\n\t}\n\tdirs, err := d.sh.List(ipfsPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tobjlist := []model.Obj{}\n\tfor _, file := range dirs {\n\t\tobjlist = append(objlist, &model.Object{ID: file.Hash, Name: file.Name, Size: int64(file.Size), IsFolder: file.Type == 1})\n\t}\n\n\treturn objlist, nil\n}\n\nfunc (d *IPFS) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {\n\tgateurl := d.gateURL.JoinPath(\"/ipfs/\", file.GetID())\n\tgateurl.RawQuery = \"filename=\" + url.QueryEscape(file.GetName())","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/ipfs_api/driver.go#L46-L82","documentation":"Returned by IPFS driver List when the configured Mode is none of \"ipfs\", \"ipns\", or \"mfs\" (or, in the outer branch, when path resolution reaches the default case). The driver cannot decide how to interpret the root path without a valid mode, so listing aborts before any shell call.","triggerScenarios":"Typo in the driver's mode config field (e.g. \"IPFS\", \"mfs \", \"msf\"); config written by an older schema using different mode names; empty Mode reaching the default branch.","commonSituations":"Hand-edited config JSON with casing errors; UI dropdown value mismatch after a driver update; default value not applied when config was created programmatically.","solutions":["Set Mode to exactly one of \"ipfs\", \"ipns\", or \"mfs\" (lowercase) in the driver addition config.","Validate mode at driver-init time (fail fast with a clear message listing valid values).","If using the UI, reselect the mode from the dropdown rather than typing it."],"exampleFix":"// before (config)\n{ \"mode\": \"IPFS\" }\n\n// after\n{ \"mode\": \"ipfs\" }","handlingStrategy":"validation","validationCode":"var validModes = map[string]bool{\"ipfs\": true, \"ipns\": true, \"mfs\": true}\nif !validModes[d.Addition.Mode] {\n    return fmt.Errorf(\"invalid mode %q, must be ipfs, ipns, or mfs\", d.Addition.Mode)\n}","typeGuard":"func isValidIPFSMode(mode string) bool {\n    switch mode {\n    case \"ipfs\", \"ipns\", \"mfs\":\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Validate mode at storage-save time in the UI","Use dropdowns, not free text, for mode fields","Fail fast in Init rather than per-operation"],"tags":["ipfs-api","config","mode-validation"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}