{"record":{"id":"925a1139421418f8","repo":"AlistGo/alist","slug":"yunpan-auth-failed-errno-d","errorCode":null,"errorMessage":"yunpan auth failed: errno=%d","messagePattern":"yunpan auth failed: errno=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/yunpan360/util.go","lineNumber":211,"sourceCode":"\t\t\t\"client_id\":     openClientID,\n\t\t\t\"client_secret\": openClientSecretForEnv(d.EcsEnv),\n\t\t\t\"grant_type\":    \"authorization_code\",\n\t\t\t\"sub_channel\":   d.SubChannel,\n\t\t\t\"api_key\":       d.APIKey,\n\t\t})\n\n\tres, err := req.Get(reqURL)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar resp OpenAuthResp\n\tif err := utils.Json.Unmarshal(res.Body(), &resp); err != nil {\n\t\treturn nil, err\n\t}\n\tif resp.Errno != 0 {\n\t\tif resp.Errmsg == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"yunpan auth failed: errno=%d\", resp.Errno)\n\t\t}\n\t\treturn nil, errors.New(resp.Errmsg)\n\t}\n\n\tauth := &OpenAuthInfo{\n\t\tAccessToken: resp.Data.AccessToken,\n\t\tQid:         resp.Data.Qid,\n\t\tToken:       resp.Data.Token,\n\t\tSubChannel:  d.SubChannel,\n\t}\n\td.cachedOpenAuth = auth\n\td.openAuthExpire = time.Now().Add(50 * time.Minute)\n\n\tcopied := *auth\n\treturn &copied, nil\n}\n\nfunc (d *Yunpan360) openBaseParams(auth *OpenAuthInfo, method string, signParams map[string]string, withSign bool) map[string]string {","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/yunpan360/util.go#L193-L229","documentation":"Thrown by Yunnan 360 Yunpan (yunpan360) driver's getOpenAuth when the Oauth.getAccessTokenByApiKey call returns a non-zero errno and the server supplied no errmsg text. The driver exchanges the configured APIKey (plus client_id/client_secret and sub_channel) for an access token at openAPIURL(d.EcsEnv); any non-zero errno aborts authentication before caching OpenAuthInfo, so every subsequent openAPI operation fails.","triggerScenarios":"Calling any yunpan360 operation that needs the open API (openGET/openPOST -> getOpenAuth) while the api_key is invalid/revoked, the EcsEnv selects the wrong endpoint, the sub_channel is not permitted, or 360's open platform rejects the credentials with an errno-only response (empty errmsg field).","commonSituations":"Expired or mistyped API key in the storage config; EcsEnv mismatch (production vs ECS endpoint); 360 open-platform app disabled or quota exhausted; token cache expired after 50 minutes and re-auth is rejected; upstream API contract change dropping errmsg.","solutions":["Verify the APIKey configured for the yunpan360 storage is valid and not revoked on 360's open platform","Check that EcsEnv matches the environment the key was issued for (openAPIURL picks the endpoint from it)","Confirm sub_channel is one allowed for the app; try the value the key was provisioned with","Test the token exchange manually with method=Oauth.getAccessTokenByApiKey and the same client_id/client_secret to see the raw errno","Map the errno against 360 open-platform error tables; if the key is revoked, issue a new one and update the driver config"],"exampleFix":"// before: invalid/mismatched config\ndriver := Yunpan360{APIKey: \"old-key\", EcsEnv: \"\", SubChannel: \"wrong\"}\n\n// after: key, env and channel consistent with the 360 open-platform app\ndriver := Yunpan360{APIKey: validKey, EcsEnv: provisionedEnv, SubChannel: \"web\"}","handlingStrategy":"retry","validationCode":"// Before mounting/first use, probe credentials with the same exchange the driver performs\nfunc probeYunpanAuth(ctx context.Context, apiKey, ecsEnv, subChannel string) error {\n    q := url.Values{}\n    q.Set(\"method\", \"Oauth.getAccessTokenByApiKey\")\n    q.Set(\"api_key\", apiKey)\n    q.Set(\"sub_channel\", subChannel)\n    req, _ := http.NewRequestWithContext(ctx, http.MethodGet, openAPIURL(ecsEnv)+\"?\"+q.Encode(), nil)\n    resp, err := http.DefaultClient.Do(req)\n    if err != nil { return err }\n    defer resp.Body.Close()\n    var r struct{ Errno int `json:\"errno\"`; Errmsg string `json:\"errmsg\"` }\n    if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { return err }\n    if r.Errno != 0 { return fmt.Errorf(\"auth probe errno=%d msg=%q\", r.Errno, r.Errmsg) }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// Go: treat as terminal config error; do not blind-retry auth with the same key\nif err := d.getOpenAuth(ctx); err != nil {\n    if strings.Contains(err.Error(), \"yunpan auth failed\") {\n        // credential/config problem: surface to user, stop retrying\n        return fmt.Errorf(\"yunpan360 credentials rejected: %w\", err)\n    }\n    return err // transport error: retryable\n}","preventionTips":["Validate the API key and EcsEnv with a probe call when configuring the storage, not at first file operation","Monitor auth failures after the 50-minute cache expiry to catch mid-session revocation early","Keep sub_channel consistent with the value the 360 app was provisioned for"],"tags":["yunpan360","auth","api","oauth","driver"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}