chenhg5/cc-connect · critical

webex: unauthorized (401) — check bot token

Error message

webex: unauthorized (401) — check bot token

What it means

errUnauthorized is a sentinel error declared in platform/webex/client.go. The Webex REST client wraps it with the failing operation name when webexapis.com returns HTTP 401, so callers can detect auth failure via errors.Is and stop retrying instead of hammering the API. It always indicates the bot token was rejected.

Source

Thrown at platform/webex/client.go:24

	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime"
	"mime/multipart"
	"net/http"
	"strconv"
	"strings"
	"time"
)

const webexBaseURL = "https://webexapis.com/v1"

// maxRetryAfter caps how long we honor a 429 Retry-After header before retrying.
const maxRetryAfter = 60 * time.Second

// errUnauthorized signals a 401 from the Webex API so callers can stop retrying.
var errUnauthorized = errors.New("webex: unauthorized (401) — check bot token")

// webexClient abstracts the Webex REST API so tests can stub it.
type webexClient interface {
	GetMe(ctx context.Context) (*person, error)
	CreateDevice(ctx context.Context) (*device, error)
	DeleteDevice(ctx context.Context, deviceURL string) error
	GetMessage(ctx context.Context, id string) (*message, error)
	DownloadFile(ctx context.Context, url string) (*downloadedFile, error)
	PostMessage(ctx context.Context, roomID, parentID, markdown string) error
	PostFile(ctx context.Context, roomID string, f *downloadedFile) error
}

// httpClient is the real webexClient backed by net/http.
type httpClient struct {
	token   string
	hc      *http.Client
	baseURL string // Webex REST base; overridable in tests.
}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Regenerate the Webex bot access token in the Webex Developer portal and update it in config.toml, then restart cc-connect.
  2. Verify the token with curl: `curl -H 'Authorization: Bearer <token>' https://webexapis.com/v1/people/me` — expect 200.
  3. Check for trailing whitespace/newlines or env-var interpolation mistakes in the configured token.
  4. Ensure you are using a bot token (not an OAuth user token) with the required scopes.

Example fix

// before (config.toml)
[platforms.webex]
access_token = "OLD_EXPIRED_TOKEN"
// after
[platforms.webex]
access_token = "Y2x...newly-generated-bot-token"
Defensive patterns

Strategy: try-catch

Validate before calling

// before starting cc-connect, verify the bot token:
tok := cfg.WebexAccessToken
req, _ := http.NewRequest("GET", "https://webexapis.com/v1/people/me", nil)
req.Header.Set("Authorization", "Bearer "+tok)
resp, err := http.DefaultClient.Do(req)
if err != nil || resp.StatusCode != 200 {
    return fmt.Errorf("webex bot token invalid (status %v)", resp.StatusCode)
}

Try / catch

if errors.Is(err, webex.ErrUnauthorized) {
    // non-retryable: alert and stop, don't loop
    slog.Error("webex auth rejected; token must be refreshed", "err", err)
    return
}

Prevention

When it happens

Trigger: Any API call routed through the client's do/request helpers (GetMe, CreateDevice, message fetches) that receives HTTP 401; also propagated by TestGetMessageUnauthorized and connectLoop when the initial connection or subsequent requests are rejected with 401.

Common situations: Expired or revoked Webex bot access token in config.toml; token copied with whitespace or from the wrong bot; environment where the token was rotated after startup; wrong integration using a user token instead of a bot token.

Understand the failure class

Related errors


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