diff --git a/src/commands/KeysCommand.ts b/src/commands/KeysCommand.ts index 3ba5522..66f8ba9 100644 --- a/src/commands/KeysCommand.ts +++ b/src/commands/KeysCommand.ts @@ -126,19 +126,40 @@ export class KeysCommand { ); const keychainFiles = files.filter((f) => f.endsWith(".keychain.json")); - const keypairData = await Promise.all( + const results = await Promise.allSettled( keypairFiles.map(async (file) => { const name = file.replace(".json", ""); const signer = await Signer.load(name); return { name, address: signer.address, - type: "keypair", + type: "keypair" as const, active: settings.activeKey === name, }; }) ); + interface KeypairEntry { + name: string; + address: string; + type: "keypair"; + active: boolean; + } + + const keypairData: KeypairEntry[] = []; + const failedKeys: string[] = []; + + for (let i = 0; i < results.length; i++) { + const r = results[i]!; + if (r.status === "fulfilled") { + keypairData.push(r.value); + } else { + failedKeys.push( + `${keypairFiles[i]!.replace(".json", "")} (${String(r.reason)})` + ); + } + } + const keychainData = keychainFiles.map((file) => { const name = file.replace(".keychain.json", ""); const config = KeychainConfig.load(name); @@ -152,6 +173,12 @@ export class KeysCommand { const data = [...keypairData, ...keychainData]; + if (failedKeys.length > 0) { + console.warn( + `Warning: Failed to load ${failedKeys.length} key(s):\n${failedKeys.map((k) => ` - ${k}`).join("\n")}` + ); + } + if (Output.isJson()) { Output.json(data); return; diff --git a/src/e2e.test.ts b/src/e2e.test.ts index fc3f878..4b13c3e 100644 --- a/src/e2e.test.ts +++ b/src/e2e.test.ts @@ -105,4 +105,29 @@ describe("keys add (dist/index.js)", () => { expect(second.status).not.toBe(0); expect(second.stdout + second.stderr).toContain("already exists"); }); + + test("gracefully handles corrupted keypair files in keys list", () => { + // Create a corrupted keypair file directly + const keysDir = require("node:path").join( + tmpHome, + ".config", + "jup", + "keys" + ); + require("node:fs").mkdirSync(keysDir, { recursive: true }); + require("node:fs").writeFileSync( + require("node:path").join(keysDir, "valid-key.json"), + JSON.stringify([1, 2, 3, 4, 5]) + ); + require("node:fs").writeFileSync( + require("node:path").join(keysDir, "corrupted.json"), + "not valid json {" + ); + + // List should succeed without crashing (exit 0), even with corrupted file + const result = runCli("keys", "list"); + expect(result.status).toBe(0); + // Should show the valid key in output + expect(result.stdout).toContain("valid-key"); + }); });