MHSanaei/3x-ui · error

API unreachable: %w

Error message

API unreachable: %w

What it means

Returned by Tgbot.TestConnection when b.GetMe() fails, i.e. the bot handle exists but the HTTPS call to api.telegram.org failed. Causes are network-level (DNS, firewall, no route to Telegram from the server's location) or API-level (401 unauthorized for an invalid/revoked token; the %w chain preserves the underlying error).

Source

Thrown at internal/web/service/tgbot/tgbot_send.go:271

	}
	if err := bot.DeleteMessage(context.Background(), &params); err != nil {
		logger.Warning("Failed to delete message:", err)
	} else {
		logger.Info("Message deleted successfully")
	}
}

// TestConnection verifies the bot token is valid and the API is reachable.
func (t *Tgbot) TestConnection() error {
	tgBotMutex.Lock()
	b := bot
	tgBotMutex.Unlock()
	if b == nil {
		return fmt.Errorf("bot not initialized")
	}
	me, err := b.GetMe(context.Background())
	if err != nil {
		return fmt.Errorf("API unreachable: %w", err)
	}
	_ = me
	return nil
}

View on GitHub (pinned to ad32144c42)

Solutions

  1. Check the wrapped error text: '401 Unauthorized' means the token is wrong/revoked — paste the current token from BotFather into panel settings and reload the bot.
  2. Verify reachability from the host: curl -sS https://api.telegram.org/bot<TOKEN>/getMe — if this hangs or is reset, fix egress (firewall rule, or route the server through a proxy/region that can reach Telegram).
  3. Retry once after fixing network: transient DNS/TLS failures self-heal; auth failures never do.
  4. Confirm system time is correct (TLS cert validation fails on skewed clocks).

Example fix

// before
me, err := b.GetMe(context.Background())
if err != nil {
    return fmt.Errorf("API unreachable: %w", err)
}

// after — distinguish auth failure from network failure for the user
me, err := b.GetMe(context.Background())
if err != nil {
    if strings.Contains(err.Error(), "401") {
        return fmt.Errorf("telegram rejected the token (401): get a fresh token from @BotFather: %w", err)
    }
    return fmt.Errorf("API unreachable (check server egress to api.telegram.org): %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight reachability check before the bot test (optional, cheap)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if _, err := net.DefaultResolver.LookupHost(ctx, "api.telegram.org"); err != nil {
    return fmt.Errorf("panel host cannot resolve api.telegram.org: %w", err)
}

Type guard

null

Try / catch

if err := tgbotSvc.TestConnection(); err != nil {
    if strings.Contains(err.Error(), "401") || strings.Contains(err.Error(), "Unauthorized") {
        // token problem: reconfigure, no retry
    } else {
        // network problem: fix egress, then retry once
    }
}

Prevention

When it happens

Trigger: TestConnection with a syntactically plausible but revoked token (Telegram returns 401), or from a host that cannot reach api.telegram.org — common on servers in regions where Telegram is blocked, or behind an egress firewall without HTTPS proxying.

Common situations: Token regenerated via BotFather after the panel saved the old one; server in a country/ISP blocking Telegram (needs a proxy the panel's bot client doesn't use); transient DNS failure; server clock skew breaking TLS.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/a8333a3db81f58c7. Report an issue: GitHub.