{"record":{"id":"f883576e7757dd19","repo":"AlistGo/alist","slug":"no-location-header-in-redirect-response","errorCode":null,"errorMessage":"no Location header in redirect response","messagePattern":"no Location header in redirect response","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/sjtu_netdisk/driver.go","lineNumber":171,"sourceCode":"\t\t\t\"user_id\":             d.UserId,\n\t\t\t\"content_disposition\": \"attachment\",\n\t\t\t\"purpose\":             \"download\",\n\t\t\t\"space_org_id\":        \"1\",\n\t\t}).\n\t\tExecute(http.MethodGet, linkURL)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// status code is not 301 and 302\n\tif resp.StatusCode() != http.StatusFound && resp.StatusCode() != http.StatusMovedPermanently {\n\t\treturn nil, fmt.Errorf(\"unexpected status code: %d\", resp.StatusCode())\n\t}\n\n\ts3URL := resp.Header().Get(\"Location\")\n\tif s3URL == \"\" {\n\t\treturn nil, fmt.Errorf(\"no Location header in redirect response\")\n\t}\n\n\t// parse TTL from S3 presigned URL's X-Amz-Expires parameter\n\tttl := 2 * time.Hour\n\tif u, parseErr := url.Parse(s3URL); parseErr == nil {\n\t\tif expiresSec, convErr := strconv.Atoi(u.Query().Get(\"X-Amz-Expires\")); convErr == nil && expiresSec > 0 {\n\t\t\tttl = time.Duration(expiresSec) * time.Second\n\t\t}\n\t}\n\n\treturn &model.Link{\n\t\tURL:        s3URL,\n\t\tExpiration: &ttl,\n\t}, nil\n}\n\nfunc (d *SJTUNetdisk) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {\n\tif err := d.refreshToken(ctx); err != nil {","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/sjtu_netdisk/driver.go#L153-L189","documentation":"The SJTU netdisk driver received the expected 301/302 redirect status but the Location header was empty, so it has no S3 presigned URL to hand back. This means the server signaled a redirect without a target — a malformed or proxied response.","triggerScenarios":"A reverse proxy (nginx/traefik) in front of the API strips or rewrites the Location header; the redirect is relative and dropped by the HTTP client configuration; the server emits 302 with an empty Location due to an internal fault.","commonSituations":"Self-hosted gateway or corporate proxy between AList and the SJTU API; the API server intermittently failing; client library following redirects automatically and re-sending to an empty target.","solutions":["Retry the request once — empty Location responses are usually transient server faults","If a proxy sits in front of the endpoint, ensure it passes the Location header through unmodified","Confirm the file is downloadable in the official SJTU client to rule out server-side state","If persistent, capture the raw response (status + headers) and report it as a driver issue"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"no Location header\") {\n    // transient or proxy-related; single retry usually resolves it\n    return retryLinkOnce()\n}","preventionTips":["Do not put rewriting proxies between AList and the SJTU API","Retry once on empty-Location before escalating","Capture headers when reporting persistent occurrences"],"tags":["sjtu-netdisk","http","headers","redirect"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}