chenhg5/cc-connect · error

matrix: device ID not available

Error message

matrix: device ID not available

What it means

crossSigningSeedsPath returns "matrix: device ID not available" when the Matrix client is nil or client.DeviceID is empty. The path for persisting cross-signing seeds is derived from the device ID, so without a device the seeds cannot be stored. Called by setupCrossSigning during E2EE bootstrap.

Source

Thrown at platform/matrix/verification.go:283

	doneContent := &event.VerificationDoneEventContent{}
	doneContent.SetRelatesTo(&event.RelatesTo{Type: event.RelReference, EventID: id.EventID(txnID)})
	if _, err := client.SendMessageEvent(ctx, evt.RoomID, event.InRoomVerificationDone, &event.Content{Parsed: doneContent}); err != nil {
		slog.Error("matrix: failed to send verification done", "error", err)
	}

	// Clean up the transaction
	helper := p.getVerificationHelper()
	if helper != nil {
		_ = helper.DismissVerification(ctx, txnID)
	}
	slog.Info("matrix: verification complete", "txn_id", txnID)
}

// crossSigningSeedsPath returns the path where cross-signing seeds are persisted.
func (p *Platform) crossSigningSeedsPath() (string, error) {
	client := p.getClient()
	if client == nil || client.DeviceID == "" {
		return "", fmt.Errorf("matrix: device ID not available")
	}
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return "", fmt.Errorf("get home dir: %w", err)
	}
	return filepath.Join(homeDir, ".cc-connect", fmt.Sprintf("matrix-cross-signing-%s.json", client.DeviceID)), nil
}

// setupCrossSigning bootstraps cross-signing for the bot's own device.
// Without cross-signing, Element shows "encrypted by a device not verified
// by its owner" on messages from the bot.
func (p *Platform) setupCrossSigning(ctx context.Context, ch *cryptohelper.CryptoHelper) {
	mach := ch.Machine()

	// If private keys are already loaded in memory, just sign our device.
	if mach.CrossSigningKeys != nil {
		p.crossSignOwnDevice(ctx, mach)
		return

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Ensure the client completed a full login so DeviceID is populated before cross-signing setup
  2. If using an access token, also supply the device ID in config or perform a whoami/login call to resolve it
  3. Check earlier logs for login failures explaining the nil client
  4. Skip cross-signing setup gracefully when no device exists yet, and retry after first successful sync

Example fix

// before
path, err := p.crossSigningSeedsPath()

// after
if p.getClient() == nil || p.getClient().DeviceID == "" {
    return fmt.Errorf("cross-signing skipped: device ID not yet available")
}
path, err := p.crossSigningSeedsPath()
Defensive patterns

Strategy: type-guard

Validate before calling

c := p.getClient()
if c == nil || c.DeviceID == "" {
    // defer cross-signing until device ID is known
}

Type guard

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

Try / catch

path, err := p.crossSigningSeedsPath()
if err != nil {
    slog.Warn("cross-signing setup deferred", "err", err)
    return
}

Prevention

When it happens

Trigger: setupCrossSigning calls crossSigningSeedsPath before the client completed login (DeviceID empty — e.g., token-only login where the server never echoed a device_id) or after the client was cleared.

Common situations: Configuring the bot with only an access token where the device ID is not resolved; login response missing device_id due to a homeserver quirk; E2EE setup racing a failed connection.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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