{"record":{"id":"5e840d438186ff9c","repo":"chenhg5/cc-connect","slug":"s-s-failed-after-token-refresh-attempt-w-ori","errorCode":null,"errorMessage":"%s: %s failed after token refresh attempt: %w (original error: %v)","messagePattern":"(.+?): (.+?) failed after token refresh attempt: %w \\(original error: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/feishu.go","lineNumber":4096,"sourceCode":"\t\t\t\treturn fmt.Errorf(\"%s: %s api call: %w\", p.tag(), op, err)\n\t\t\t}\n\t\t\tif !resp.Success() {\n\t\t\t\treturn fmt.Errorf(\"%s: %s failed code=%d msg=%s\", p.tag(), op, resp.Code, resp.Msg)\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t})\n}\n\nfunc (p *Platform) withFreshTenantAccessTokenRetry(ctx context.Context, operation string, fn feishuRequestFunc) error {\n\terr := fn(p.client)\n\tif !isTenantAccessTokenInvalid(err) {\n\t\treturn err\n\t}\n\n\tfreshToken, refreshErr := p.fetchFreshTenantAccessToken(ctx)\n\tif refreshErr != nil {\n\t\treturn fmt.Errorf(\"%s: %s failed after token refresh attempt: %w (original error: %v)\", p.tag(), operation, refreshErr, err)\n\t}\n\n\tslog.Warn(p.tag()+\": retrying request with fresh tenant access token\", \"operation\", operation)\n\treturn fn(p.replayAPIClient(), larkcore.WithTenantAccessToken(freshToken))\n}\n\nfunc (p *Platform) fetchFreshTenantAccessToken(ctx context.Context) (string, error) {\n\tresp, err := p.replayAPIClient().GetTenantAccessTokenBySelfBuiltApp(ctx, &larkcore.SelfBuiltTenantAccessTokenReq{\n\t\tAppID:     p.appID,\n\t\tAppSecret: p.appSecret,\n\t})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"%s: fetch tenant access token: %w\", p.tag(), err)\n\t}\n\tif !resp.Success() {\n\t\treturn \"\", fmt.Errorf(\"%s: fetch tenant access token code=%d msg=%s\", p.tag(), resp.Code, resp.Msg)\n\t}\n\tif strings.TrimSpace(resp.TenantAccessToken) == \"\" {","sourceCodeStart":4078,"sourceCodeEnd":4114,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/feishu.go#L4078-L4114","documentation":"Raised by withFreshTenantAccessTokenRetry: the original API call failed with an invalid-tenant-access-token error, a fresh token fetch was attempted, but fetching the new token itself failed. The error chains both the refresh failure (%w) and the original API error for diagnosis.","triggerScenarios":"An Im.Message reply/create call fails with isTenantAccessTokenInvalid(err)==true, and the subsequent p.fetchFreshTenantAccessToken(ctx) returns an error (network failure or API rejection while obtaining the token).","commonSituations":"App secret revoked or rotated in the Feishu console while the service runs, Feishu auth endpoint unreachable, or app disabled — token refresh is impossible so the original token-expiry error persists.","solutions":["Inspect the wrapped refreshErr: if it's a network error, check connectivity to the Feishu token endpoint.","Verify app_id/app_secret are still valid and unchanged in config.toml.","Check the app is enabled and not deactivated in the Feishu developer console.","Restart the service after fixing credentials so cached state is rebuilt."],"exampleFix":"// before\nreturn fmt.Errorf(\"%s: %s failed after token refresh attempt: %w (original error: %v)\", p.tag(), operation, refreshErr, err)\n// after\nslog.Error(p.tag()+\": token refresh failed\", \"operation\", operation, \"refreshErr\", refreshErr, \"originalErr\", err)\nreturn fmt.Errorf(\"%s: %s failed after token refresh attempt: %w (original error: %v)\", p.tag(), operation, refreshErr, err)","handlingStrategy":"retry","validationCode":"// startup credential check\nif _, err := fetchFreshTenantAccessToken(ctx); err != nil {\n\treturn fmt.Errorf(\"invalid feishu credentials: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := doFeishuCall(ctx)\nif err != nil && strings.Contains(err.Error(), \"token refresh attempt\") {\n\t// credentials invalid or auth endpoint down: alert operator, do not hot-retry\n\tnotifyOps(err)\n}","preventionTips":["Validate credentials at startup, not just at first API failure.","Alert on token-refresh failures — they mean auth is broken, not transient.","Track app secret rotations in the Feishu console.","Keep a bounded refresh retry to avoid hammering the auth endpoint."],"tags":["feishu","lark","auth","token","retry"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}