chenhg5/cc-connect · error

subscribe: %w

Error message

subscribe: %w

What it means

startWebhook wraps the error from p.subscribe, which registers the webhook URL with the MAX API. This is the inner layer beneath the "max: start webhook" error and indicates the subscription HTTP call itself failed.

Source

Thrown at platform/max/max.go:237

	mux.HandleFunc(p.webhookPath, p.webhookHandler)
	srv := &http.Server{
		Addr:              p.webhookListen,
		Handler:           mux,
		ReadHeaderTimeout: 10 * time.Second,
	}
	// Caller (Start) already holds p.mu, so assign directly — re-locking
	// a non-reentrant sync.RWMutex would deadlock.
	p.webServer = srv

	go func() {
		slog.Info("max: webhook listening", "addr", p.webhookListen, "path", p.webhookPath, "url", p.webhookURL)
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			slog.Error("max: webhook listener stopped", "err", err)
		}
	}()

	if err := p.subscribe(ctx, p.webhookURL); err != nil {
		return fmt.Errorf("subscribe: %w", err)
	}
	slog.Info("max: webhook subscribed", "url", p.webhookURL)

	// MAX has been observed to silently drop the webhook subscription
	// server-side without any delivery error. The documented 8h failure
	// window does not match the observed cadence (drops every 25–60min),
	// so we periodically re-POST the subscription. MAX overwrites the
	// existing registration in-place, so re-subscribing is idempotent.
	if p.resubscribeInterval > 0 {
		go p.resubscribeLoop(ctx)
	}
	return nil
}

func (p *Platform) resubscribeLoop(ctx context.Context) {
	t := time.NewTicker(p.resubscribeInterval)
	defer t.Stop()
	for {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check the wrapped error: for "HTTP 4xx/5xx" inspect the API status and response body.
  2. Verify the bot token is valid and has permission to manage subscriptions.
  3. Confirm the webhook URL is publicly reachable over HTTPS from MAX servers.
  4. Rely on the built-in resubscribe loop for transient drops; only intervene if failures are persistent.
Defensive patterns

Strategy: retry

Validate before calling

// pre-check token validity
resp, err := http.Get("https://botapi.max.ru/me?access_token=" + token)
// err != nil or non-200 → do not attempt webhook setup

Try / catch

if err := p.Start(handler); err != nil {
    if strings.Contains(err.Error(), "subscribe:") {
        // schedule a delayed restart with backoff
        time.AfterFunc(backoff, func() { retryStart() })
    }
}

Prevention

When it happens

Trigger: Start (or the resubscribe loop) invoking subscribe with a webhook URL that the MAX API rejects: network failure, invalid URL, HTTP 4xx/5xx response, or invalid bot token.

Common situations: Bot token revoked/missing subscription scope, webhook URL not HTTPS or unreachable by MAX servers, transient network outage during a periodic resubscribe.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/0f5253a7c3d17660. Report an issue: GitHub.