chenhg5/cc-connect · error

device ID not available from whoami

Error message

device ID not available from whoami

What it means

initCrypto in platform/matrix/e2ee.go:170 requires a device ID to set up end-to-end encryption, but client.DeviceID is empty after whoami. The library throws "device ID not available from whoami" because the Matrix crypto helper cannot be keyed without a device ID.

Source

Thrown at platform/matrix/e2ee.go:170

	// Bootstrap cross-signing
	p.setupCrossSigning(ctx, ch)

	// client.Crypto must be set for VerificationHelper
	client.Crypto = ch

	// Initialize SAS verification helper
	if p.autoVerify {
		if vErr := p.initVerification(ctx, ch); vErr != nil {
			slog.Warn("matrix: verification helper not available", "error", vErr)
		} else {
			slog.Info("matrix: SAS verification enabled", "mode", "auto-verify")
		}
	}
}

func (p *Platform) initCrypto(ctx context.Context, client *mautrix.Client) (*cryptohelper.CryptoHelper, error) {
	if client.DeviceID == "" {
		return nil, fmt.Errorf("device ID not available from whoami")
	}

	homeDir, err := os.UserHomeDir()
	if err != nil {
		return nil, fmt.Errorf("get home dir: %w", err)
	}
	cryptoDir := filepath.Join(homeDir, ".cc-connect")
	if err := os.MkdirAll(cryptoDir, 0o700); err != nil {
		return nil, fmt.Errorf("create data dir: %w", err)
	}
	dbPath := filepath.Join(cryptoDir, fmt.Sprintf("matrix-crypto-%s.db", client.DeviceID))

	// Derive a stable pickle key from the access token
	h := sha256.Sum256([]byte(p.accessToken))
	pickleKey := make([]byte, 32)
	copy(pickleKey, h[:])

	return p.tryInitCrypto(ctx, client, pickleKey, dbPath, false)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Log in via mautrix's Login API with DeviceID set (e.g. client.Login with ReqLogin{DeviceID: ...}) instead of relying on whoami
  2. Supply an explicit device ID in the client configuration (mautrix.NewClient with DeviceID param)
  3. Disable E2EE if a device ID cannot be obtained (skip initE2EE) and run without encryption
  4. Check homeserver whoami response actually includes device_id (server-side config/version issue)

Example fix

// before
client, _ := mautrix.NewClient(homeserver, "", token)
client.DeviceID = "" // set from whoami, may be empty
// after
client, _ := mautrix.NewClient(homeserver, "", token)
if client.DeviceID == "" {
    client.DeviceID = id.DeviceID(cfg.MatrixDeviceID) // from config/login
}
Defensive patterns

Strategy: validation

Validate before calling

if client.DeviceID == "" {
    return errors.New("e2ee requires a device ID; set it via login or config before enabling e2ee")
}

Type guard

func hasDeviceID(c *mautrix.Client) bool { return c != nil && c.DeviceID != "" }

Try / catch

crypto, err := p.initCrypto(ctx, client)
if err != nil {
    if strings.Contains(err.Error(), "device ID not available") {
        slog.Warn("E2EE disabled: no device ID from whoami; re-login to obtain one")
        return nil // degrade gracefully without encryption
    }
    return fmt.Errorf("init e2ee: %w", err)
}

Prevention

When it happens

Trigger: Calling initE2EE when the mautrix client was constructed with access-token login (whoami) that did not yield a device_id — e.g. token obtained outside the library, no device_id field in the whoami response, or server omitting it.

Common situations: Using a pre-existing access token created without a device_id (e.g. from an older login or manual curl); Matrix homeserver versions that omit device_id in whoami responses; logging in via a custom flow instead of mautrix's Login API.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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