{"record":{"id":"8d652a2ff4c3eb0a","repo":"fish2018/pansou","slug":"s-hsid-s-api-s","errorCode":null,"errorMessage":"[%s] hsid=%s链接API错误: %s","messagePattern":"\\[(.+?)\\] hsid=(.+?)链接API错误: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/haisou/haisou.go","lineNumber":426,"sourceCode":"\tif resp.StatusCode != 200 {\n\t\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s链接请求返回状态码: %d\", p.Name(), hsid, resp.StatusCode)\n\t}\n\n\t// 读取响应体\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s读取响应失败: %w\", p.Name(), hsid, err)\n\t}\n\n\t// 解析响应\n\tvar apiResp FetchAPIResponse\n\tif err := json.Unmarshal(body, &apiResp); err != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s链接JSON解析失败: %w\", p.Name(), hsid, err)\n\t}\n\n\t// 检查API响应状态\n\tif apiResp.Code != 0 {\n\t\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s链接API错误: %s\", p.Name(), hsid, apiResp.Msg)\n\t}\n\n\t// 根据平台类型构建完整的分享链接\n\tshareURL := buildShareURL(platform, apiResp.Data.ShareCode)\n\tif shareURL == \"\" {\n\t\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s不支持的网盘平台: %s\", p.Name(), hsid, platform)\n\t}\n\n\t// 获取密码\n\tpassword := \"\"\n\tif apiResp.Data.SharePwd != nil {\n\t\tpassword = *apiResp.Data.SharePwd\n\t}\n\n\tif DebugLog {\n\t\tfmt.Printf(\"[%s] hsid=%s成功获取链接: %s password=%s\\n\", p.Name(), hsid, shareURL, password)\n\t}\n","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/haisou/haisou.go#L408-L444","documentation":"This error is thrown when the share-link API responded with valid JSON but a non-zero Code field, i.e. a business-level rejection from the haisou upstream. The API's own message (apiResp.Msg) is included — typical upstream reasons are invalid/expired hsid, missing quota, or authentication issues with the upstream aggregator.","triggerScenarios":"fetchShareLink receives a successfully-parsed FetchAPIResponse whose Code != 0.","commonSituations":"hsid is stale/deleted upstream (share already revoked); upstream account quota exhausted; API key/token missing or expired; upstream service temporarily rejecting requests.","solutions":["Read apiResp.Msg in the error and act on the upstream reason","Verify the hsid exists/is still valid before conversion (or handle revocation gracefully)","Check upstream API key/token validity and renewal","Retry on transient upstream codes; fail fast on permanent ones (invalid hsid)"],"exampleFix":"// before\nif apiResp.Code != 0 {\n\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s链接API错误: %s\", p.Name(), hsid, apiResp.Msg)\n}\n// after\nif apiResp.Code != 0 {\n\tif apiResp.Code == codeShareRevoked {\n\t\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s分享已失效(上游code=%d): %s\", p.Name(), hsid, apiResp.Code, apiResp.Msg) // permanent, do not retry\n\t}\n\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s链接API错误: code=%d msg=%s\", p.Name(), hsid, apiResp.Code, apiResp.Msg)\n}","handlingStrategy":"try-catch","validationCode":"// Code is only known post-response; defend by classifying codes\nswitch {\ncase apiResp.Code == 0:\n\t// proceed\ncase isPermanentCode(apiResp.Code):\n\t// do not retry\ndefault:\n\t// retry with backoff\n}","typeGuard":"func upstreamAccepted(resp FetchAPIResponse) bool { return resp.Code == 0 }","tryCatchPattern":"if apiResp.Code != 0 {\n\treturn fmt.Errorf(\"share link API error: code=%d msg=%s\", apiResp.Code, apiResp.Msg)\n}","preventionTips":["Validate hsid freshness before conversion; treat revocation as permanent","Keep upstream credentials valid and renewed","Classify upstream codes into retryable vs permanent and handle each path","Log apiResp.Code/Msg to track upstream issues"],"tags":["api","upstream","error-response","go"],"backgroundTag":"api-error-response","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}