diff --git a/projects/keepkey-vault/src/bun/engine-controller.ts b/projects/keepkey-vault/src/bun/engine-controller.ts index e5e77e0..657bdee 100644 --- a/projects/keepkey-vault/src/bun/engine-controller.ts +++ b/projects/keepkey-vault/src/bun/engine-controller.ts @@ -510,6 +510,11 @@ export class EngineController extends EventEmitter { let usbDetected = false let lastError: string | null = null + // Clear stale keyring entries before attempting to pair — without this, + // a previous failed pairing leaves the transport in "opened" state and + // WebUSB rejects with "cannot connect an already-connected connection". + try { await this.keyring.removeAll() } catch (_) {} + // Try WebUSB first (modern firmware, PID 0x0002) console.log('[Engine] Scanning for WebUSB device...') try { diff --git a/projects/keepkey-vault/src/mainview/components/OobSetupWizard.tsx b/projects/keepkey-vault/src/mainview/components/OobSetupWizard.tsx index f465c52..ee878ee 100644 --- a/projects/keepkey-vault/src/mainview/components/OobSetupWizard.tsx +++ b/projects/keepkey-vault/src/mainview/components/OobSetupWizard.tsx @@ -257,6 +257,15 @@ export function OobSetupWizard({ onComplete, onSetupInProgress, onWordCountChang return () => onSetupInProgress?.(false) }, [onSetupInProgress]) + // ── Clear stale setup errors on reconnect ───────────────────────────── + // LIBUSB_TRANSFER_ERROR etc. from a previous session should not persist + // once the device is back in a connected state with real features. + useEffect(() => { + if (deviceStatus.state === 'needs_init' || deviceStatus.state === 'ready') { + setSetupError(null) + } + }, [deviceStatus.state]) + // ── Welcome → user clicks to advance ─────────────────────────────────── // Only enable "Get Started" when real device features are available. // connected_unpaired has no features yet — routing from that state would