{"record":{"id":"150f7852c46d7e72","repo":"AlistGo/alist","slug":"request-failed-s-150f78","errorCode":null,"errorMessage":"request failed: %s","messagePattern":"request failed: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/seafile/util.go","lineNumber":68,"sourceCode":"\tvar (\n\t\tres *resty.Response\n\t\terr error\n\t)\n\tfor i := 0; i < 2; i++ {\n\t\tres, err = req.Execute(method, full)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif res.StatusCode() != 401 { // Unauthorized\n\t\t\tbreak\n\t\t}\n\t\terr = d.getToken()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif res.StatusCode() >= 400 {\n\t\treturn nil, fmt.Errorf(\"request failed: %s\", res.String())\n\t}\n\treturn res.Body(), nil\n}\n\nfunc (d *Seafile) getRepoAndPath(fullPath string) (repo *LibraryInfo, path string, err error) {\n\tlibraryMap := d.libraryMap\n\trepoId := d.Addition.RepoId\n\tif repoId != \"\" {\n\t\tif len(repoId) == 36 /* uuid */ {\n\t\t\tfor _, library := range libraryMap {\n\t\t\t\tif library.Id == repoId {\n\t\t\t\t\treturn library, fullPath, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tvar repoName string\n\t\tstr := fullPath[1:]","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/seafile/util.go#L50-L86","documentation":"Thrown by the Seafile driver's request helper after the response status is >= 400. The helper first retries once on 401 by re-fetching an auth token, so any other 4xx/5xx (or a 401 that survived the token refresh) reaches this check. The message embeds the full response body, so the Seafile server's own error text is included.","triggerScenarios":"Any Seafile API call (listing, upload, link, delete) whose response code is >= 400: expired or invalid token whose getToken() refresh also fails or returns a token the server still rejects (401 twice), a library/repo ID that no longer exists (404), permission denied (403), or a Seafile server-side 5xx.","commonSituations":"Wrong Seafile server URL or repository ID in the mount config; password/token changed or revoked since it was saved; the account lost access to the library; Seafile server upgraded and the API endpoint moved; reverse proxy in front of Seafile returning HTML error pages.","solutions":["Read the response body inside the error text — Seafile usually states the exact cause (e.g. 'Library not found', 'Incorrect password')","Verify the Addition config: server address, repo ID (36-char UUID or library name), username and password/token","Re-enter credentials so a fresh token is obtained, then retry the operation","Confirm the account still has access to the target library on the Seafile web UI","Check the reverse proxy / Seafile server logs if the body shows 5xx or an HTML error page"],"exampleFix":"// before: opaque failure\nerr := d.request(ctx, url)\n// after: surface status + body for diagnosis\nif res.StatusCode() >= 400 {\n    return nil, fmt.Errorf(\"request failed: status=%d body=%s\", res.StatusCode(), res.String())\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := doSeafileOp()\nif err != nil {\n    if strings.Contains(err.Error(), \"request failed:\") {\n        // body text from Seafile is embedded; branch on 'Unauthorized'/'not found'\n        if strings.Contains(err.Error(), \"Unauthorized\") { refreshCreds(); retry() }\n    }\n}","preventionTips":["Keep Seafile credentials and repo ID current in the storage config","Treat 401-containing messages as a signal to re-authenticate, not to keep retrying","Log the full error — it embeds the server's response body"],"tags":["seafile","http","auth","driver"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}