{"record":{"id":"d5aa87204d27a5fa","repo":"chenhg5/cc-connect","slug":"s-s-retry-cancelled-w-last-error-v","errorCode":null,"errorMessage":"%s: %s retry cancelled: %w (last error: %v)","messagePattern":"(.+?): (.+?) retry cancelled: %w \\(last error: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/feishu.go","lineNumber":4227,"sourceCode":"\t\tif !isTransientError(lastErr) {\n\t\t\treturn lastErr\n\t\t}\n\t\tif attempt == maxTransientRetries {\n\t\t\tbreak\n\t\t}\n\t\t// Add jitter: up to +25% of delay to spread out concurrent retries.\n\t\tjitter := time.Duration(rand.Int64N(int64(delay / 4)))\n\t\tactualDelay := delay + jitter\n\t\tslog.Warn(p.tag()+\": transient error, retrying\",\n\t\t\t\"operation\", operation,\n\t\t\t\"attempt\", attempt+1,\n\t\t\t\"max_retries\", maxTransientRetries,\n\t\t\t\"delay\", actualDelay,\n\t\t\t\"error\", lastErr,\n\t\t)\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn fmt.Errorf(\"%s: %s retry cancelled: %w (last error: %v)\", p.tag(), operation, ctx.Err(), lastErr)\n\t\tcase <-time.After(actualDelay):\n\t\t}\n\t\tdelay = min(delay*2, transientRetryMaxDelay)\n\t}\n\treturn fmt.Errorf(\"%s failed after %d retries: %w\", operation, maxTransientRetries, lastErr)\n}\n\n// ── Issue #1618: fail-closed + supervised retry for bot open_id ──\n//\n// When the Feishu/Lark bot-info API call fails at startup (transient\n// proxy/VPN/DNS outage, server hiccup, etc.), the bot's open_id stays\n// unknown. The previous behaviour read this as \"group mention filter\n// off\", so the bot would reply to every group message for the rest of\n// the process lifetime — a 3h10m window in the user's incident where\n// the bot suddenly became a loud responder with no way for operators\n// to notice. The functions below:\n//\n//   - wrap the initial fetch in transient retry so most startup","sourceCodeStart":4209,"sourceCodeEnd":4245,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/feishu.go#L4209-L4245","documentation":"withTransientRetry: the context was cancelled while sleeping between retry attempts; the cancellation error is wrapped together with the last transient error so callers can see both. Expected during shutdown or operation timeouts.","triggerScenarios":"Thrown at platform/feishu/feishu.go:4227 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Normal during shutdown — no action needed","If frequent, increase the operation timeout or lower the retry delay"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}