{"record":{"id":"dea2fc0cf536b149","repo":"Tencent/WeKnora","slug":"list-personal-repos-w","errorCode":null,"errorMessage":"list personal repos: %w","messagePattern":"list personal repos: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/datasource/connector/yuque/connector.go","lineNumber":91,"sourceCode":"\trepos := make(map[int64]v2Repo)\n\n\t// Team token: /api/v2/user returns type=\"Group\" — the token represents a team,\n\t// not a personal user. In this case, directly list the team's own repos instead\n\t// of going through the personal-repos + user-groups flow.\n\tif me.Type == \"Group\" {\n\t\tlogger.Infof(ctx, \"[Yuque] detected team token (type=Group, login=%s), listing team repos directly\", me.Login)\n\t\tteamRepos, err := cli.ListGroupRepos(ctx, me.Login)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"list team repos: %w\", err)\n\t\t}\n\t\tfor _, r := range teamRepos {\n\t\t\trepos[r.ID] = r\n\t\t}\n\t} else {\n\t\t// Personal token flow: list user's own repos + repos from joined groups.\n\t\tpersonal, err := cli.ListUserRepos(ctx, me.Login)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"list personal repos: %w\", err)\n\t\t}\n\t\tfor _, r := range personal {\n\t\t\tif _, ok := repos[r.ID]; !ok {\n\t\t\t\trepos[r.ID] = r\n\t\t\t}\n\t\t}\n\n\t\tgroups, err := cli.ListUserGroups(ctx, me.ID)\n\t\tif err != nil {\n\t\t\t// Yuque returns 404 when the user has not joined any groups (teams),\n\t\t\t// instead of an empty list. Treat this as \"no groups\" and continue\n\t\t\t// — personal repos were already fetched above.\n\t\t\tlogger.Warnf(ctx, \"[Yuque] list user groups failed (treating as empty): %v\", err)\n\t\t\tgroups = nil\n\t\t}\n\t\tfor _, g := range groups {\n\t\t\tteamRepos, err := cli.ListGroupRepos(ctx, g.Login)\n\t\t\tif err != nil {","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/datasource/connector/yuque/connector.go#L73-L109","documentation":"This error wraps a failure from cli.ListUserRepos during ListResources' personal-token flow. The /me response indicated a personal user, so the connector fetches the user's own repos; any API-level failure there is wrapped with this prefix while preserving the cause with %w.","triggerScenarios":"A personal Yuque token is configured and ListUserRepos(me.Login) returns an error — invalid/expired token, network failure, rate limiting, or a user whose repos endpoint returns an unexpected error.","commonSituations":"Personal access token expired or revoked; token created without repo read scope; user account deactivated; yuque API outage or 429 rate limit under heavy polling.","solutions":["Verify the personal token with curl https://api.yuque.com/api/v2/user and regenerate it if it returns 401","Ensure the token has read scope for the user's repositories (read_repo or broader)","Inspect the wrapped error: 429 means back off/poll less frequently; 5xx means retry later or check Yuque status","Confirm the connector host can reach api.yuque.com (proxy/DNS issues)"],"exampleFix":"// before\npersonal, err := cli.ListUserRepos(ctx, me.Login)\nif err != nil {\n    return nil, fmt.Errorf(\"list personal repos: %w\", err)\n}\n// after\npersonal, err := cli.ListUserRepos(ctx, me.Login)\nif err != nil {\n    return nil, fmt.Errorf(\"list personal repos (user=%s): %w\", me.Login, err)\n}","handlingStrategy":"try-catch","validationCode":"// Probe the personal token before configuring:\n// GET https://api.yuque.com/api/v2/user with X-Auth-Token\n// treat 401 as invalid token, 403 as missing scope","typeGuard":"var apiErr *yuque.APIError\nif errors.As(err, &apiErr) {\n    switch apiErr.StatusCode {\n    case 401: // re-auth\n    case 429: // backoff\n    }\n}","tryCatchPattern":"items, err := ds.ListResources(ctx, cfg)\nif err != nil {\n    var apiErr *yuque.APIError\n    if errors.As(err, &apiErr) && apiErr.StatusCode == 429 {\n        time.Sleep(backoff)\n        items, err = ds.ListResources(ctx, cfg)\n    }\n    if err != nil {\n        log.Printf(\"personal repo listing failed: %v\", err)\n    }\n}","preventionTips":["Test the token with a /user API call before saving config","Keep a documented token rotation process","Check token scopes include repository read","Monitor Yuque API rate limits and back off on 429"],"tags":["yuque","api-error","authentication","connector"],"backgroundTag":"upstream-api-call-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}