chenhg5/cc-connect · warning
reconstruct reply ctx: %w
Error message
reconstruct reply ctx: %w
What it means
This error wraps the failure of ReplyContextReconstructor.ReconstructReplyCtx during a restart notification. After the process restarts (e.g. via /restart + syscall.Exec), the engine must rebuild the platform-specific reply context (chat id, message id, thread info) from the stored session key so it can push a 'restart succeeded' message. If the platform adapter cannot reconstruct that context — usually because the referenced chat/session no longer exists, the stored key is stale after the restart, or the platform API call to look it up failed — dispatchRestartNotify aborts with 'reconstruct reply ctx: %w'.
Source
Thrown at core/engine.go:291
}
e.pendingRestartMu.Unlock()
}
// dispatchRestartNotify sends the notify to the target platform with up
// to 3 attempts (initial + 2 retries) on transient failure. The
// platform must already be ready when this is called.
func (e *Engine) dispatchRestartNotify(req *RestartRequest) error {
p := e.lookupReadyPlatform(req.Platform)
if p == nil {
return fmt.Errorf("platform %q not ready", req.Platform)
}
rc, ok := p.(ReplyContextReconstructor)
if !ok {
return fmt.Errorf("platform %q does not support ReconstructReplyCtx", req.Platform)
}
rctx, err := rc.ReconstructReplyCtx(req.SessionKey)
if err != nil {
return fmt.Errorf("reconstruct reply ctx: %w", err)
}
text := e.i18n.T(MsgRestartSuccess)
if CurrentVersion != "" {
text += fmt.Sprintf(" (%s)", CurrentVersion)
}
backoffs := []time.Duration{0, 500 * time.Millisecond, 1500 * time.Millisecond}
var lastErr error
for attempt, wait := range backoffs {
if wait > 0 {
time.Sleep(wait)
}
if err := e.waitOutgoing(p); err != nil {
lastErr = fmt.Errorf("wait outgoing: %w", err)
slog.Warn("restart notify: wait outgoing failed",
"platform", req.Platform, "attempt", attempt+1, "error", err)
continue
}View on GitHub (pinned to 4000b2338a)
Solutions
- Inspect the wrapped cause (the %w inner error) in logs to see whether it is an API/auth failure or a not-found lookup; fix that underlying issue first.
- Re-trigger the conversation: send any message in the original chat so the platform re-registers a fresh reply context, then retry /restart.
- Verify the session key stored in the pending RestartRequest still points at an existing chat (not a deleted/archived channel or DM the bot left).
- Check platform credentials (token expiry) — re-authenticate or refresh the bot token before restarting again.
- If the platform API was transiently down, wait and retry /restart; the notify is not critical to the restart itself.
Example fix
// before: reconstruct fails with stale session key after bot was removed
// engine: rctx, err := rc.ReconstructReplyCtx(req.SessionKey)
// after: guard the caller — only request restart notify for a live, reachable chat
if rc, ok := p.(ReplyContextReconstructor); ok {
if _, err := rc.ReconstructReplyCtx(req.SessionKey); err != nil {
slog.Warn("skip restart notify, ctx unreachable", "err", err)
return nil // proceed with restart without notification
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: verify reconstructability before scheduling a restart notify
if rc, ok := platform.(core.ReplyContextReconstructor); ok {
if _, err := rc.ReconstructReplyCtx(sessionKey); err != nil {
log.Printf("restart notify will fail for %s: %v", sessionKey, err)
}
} Type guard
rc, ok := p.(core.ReplyContextReconstructor); if !ok { /* skip notify */ } Try / catch
if err := engine.NotifyRestart(req); err != nil {
var ctxErr error
if errors.As(err, &ctxErr) && strings.Contains(err.Error(), "reconstruct reply ctx") {
slog.Warn("restart completed but notify failed; chat unreachable", "err", err)
} else {
slog.Error("restart notify failed", "err", err)
}
} Prevention
- Send a message in the target chat shortly before /restart to confirm the reply context is live.
- Treat restart-notify failure as non-fatal: the restart itself already succeeded.
- Persist session keys only for chats the bot is still a member of; prune stale ones.
- Monitor the wrapped inner error for auth/token expiry and refresh credentials proactively.
When it happens
Trigger: Engine.dispatchRestartNotify is called by runPendingRestartNotify after a restart; p.(ReplyContextReconstructor) succeeded but rc.ReconstructReplyCtx(req.SessionKey) returned an error (platform API lookup failed, session key refers to a deleted/archived chat, bot removed from the chat, or transient API/auth failure).
Common situations: User deleted the chat or removed the bot between invoking /restart and process re-exec; session keys persisted from an old workspace/config pointing at chats that no longer exist; platform token expired during the restart window; Feishu/Telegram API temporarily unreachable right after process restart.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- bridge: invalid reply context type %T
- wait outgoing: %w
- platform %q does not support proactive messaging (cron)
- resolve cron reply target: %w
- cloud_web: reconstruct_reply not supported by gateway
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/7a9dcf001679e9cf.
Report an issue: GitHub.