sipeed/picoclaw · error

get device ID via whoami: %w

Error message

get device ID via whoami: %w

What it means

Thrown by MatrixChannel.initCrypto when the logged-in client has no DeviceID and the homeserver lookup POST /_matrix/client/v3/account/whoami fails (pkg/channels/matrix/matrix.go:375). The crypto store is keyed by device ID, so it must be resolved before cryptoHelper.Init. The homeserver rejects whoami with 401 M_UNKNOWN_TOKEN for an invalid/expired access token; network failures, DNS errors, and a canceled startup context also surface here. The DB is closed on this path.

Source

Thrown at pkg/channels/matrix/matrix.go:375

	}

	// Wrap with dbutil for dialect support
	wrappedDB, err := dbutil.NewWithDB(db, sqliteDriver)
	if err != nil {
		_ = db.Close()
		return fmt.Errorf("wrap database: %w", err)
	}

	cryptoHelper, err := cryptohelper.NewCryptoHelper(c.client, []byte(c.config.CryptoPassphrase), wrappedDB)
	if err != nil {
		return fmt.Errorf("create crypto helper: %w", err)
	}

	if c.client.DeviceID == "" {
		resp, whoamiErr := c.client.Whoami(ctx)
		if whoamiErr != nil {
			_ = db.Close()
			return fmt.Errorf("get device ID via whoami: %w", whoamiErr)
		}
		c.client.DeviceID = resp.DeviceID
	}

	if err = cryptoHelper.Init(ctx); err != nil {
		cryptoHelper.Close()
		return fmt.Errorf("init crypto helper: %w", err)
	}

	c.client.Crypto = cryptoHelper
	c.cryptoHelper = cryptoHelper

	logger.InfoC("matrix", "Crypto helper initialized successfully")
	return nil
}

func markdownToHTML(md string) string {
	extensions := (parser.CommonExtensions | parser.NoEmptyLineBeforeBlock) &^ parser.DefinitionLists

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Verify the token out-of-band: curl -H 'Authorization: Bearer <token>' https://homeserver/_matrix/client/v3/account/whoami — 401 means regenerate the token and update config
  2. Check homeserver reachability and the configured server URL; fix DNS/proxy issues
  3. Re-login to obtain a fresh token (and persist device_id to skip the whoami path next start)
  4. Retry startup if it was a transient network failure

Example fix

# diagnose
 curl -s -H "Authorization: Bearer $MATRIX_TOKEN" \
   https://matrix.example.org/_matrix/client/v3/account/whoami
 # {"errcode":"M_UNKNOWN_TOKEN","error":"Invalid token"} -> token expired: re-login and update config
Defensive patterns

Strategy: retry

Validate before calling

// cheap token liveness check before starting the channel
func tokenAlive(ctx context.Context, hs, token string) error {
	req, _ := http.NewRequestWithContext(ctx, http.MethodGet, hs+"/_matrix/client/v3/account/whoami", nil)
	req.Header.Set("Authorization", "Bearer "+token)
	resp, err := http.DefaultClient.Do(req)
	if err != nil { return err }
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusUnauthorized {
		return errors.New("access token invalid/expired: re-login required")
	}
	return nil
}

Try / catch

for attempt := 0; attempt < 5; attempt++ {
	err := matrixCh.Start(ctx)
	if err == nil { break }
	var httpErr mautrix.HTTPError
	if errors.As(err, &httpErr) && httpErr.RespError != nil && httpErr.RespError.Errcode == "M_UNKNOWN_TOKEN" {
		refreshAccessToken() // permanent: rotate token, do not retry
		continue
	}
	time.Sleep(backoff(attempt)) // transient network: backoff and retry
}

Prevention

When it happens

Trigger: Logging in with an access token that was revoked (password changed, sessions invalidated, token rotated by another bot instance); homeserver unreachable (wrong URL, DNS failure, firewall); reverse proxy returning 5xx on the client API; startup context canceled before device discovery; using a token whose device was deleted server-side.

Common situations: Long-lived bot deployments where the shared access token expired or was invalidated by the user; homeserver migration or restart during bot startup; typo in the homeserver URL; load balancer health-check gaps. DeviceID is typically empty when authenticating by token without a stored device_id from a previous run.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/b45be312bb600eb7. Report an issue: GitHub.