diff --git a/apps/web/src/app/setup/page.tsx b/apps/web/src/app/setup/page.tsx index 423eb25c..da16ff00 100644 --- a/apps/web/src/app/setup/page.tsx +++ b/apps/web/src/app/setup/page.tsx @@ -1902,7 +1902,8 @@ export default function SetupPage() { setGeminiError(""); }} onPaste={(e) => { - const pasted = e.clipboardData.getData("text"); + e.preventDefault(); + const pasted = e.clipboardData.getData("text").trim(); if (pasted) { setGeminiKey(pasted); setGeminiValidated(false); diff --git a/packages/agent-adapters/src/gemini.ts b/packages/agent-adapters/src/gemini.ts index 37a7c0e5..9b0ddfdb 100644 --- a/packages/agent-adapters/src/gemini.ts +++ b/packages/agent-adapters/src/gemini.ts @@ -164,6 +164,13 @@ export class GeminiAdapter implements AgentAdapter { let hasError = false; let lastAssistantMessage: string | undefined; + // Check for JSON error messages embedded in non-JSON output + const apiKeyErrorMatch = logs.match(/API key not valid|API_KEY_INVALID/i); + if (apiKeyErrorMatch) { + errorMessage = "API key not valid. Please pass a valid API key."; + hasError = true; + } + for (const line of logs.split("\n")) { if (!line.trim()) continue; diff --git a/packages/shared/src/error-classifier.test.ts b/packages/shared/src/error-classifier.test.ts index dfc847f2..22a8d277 100644 --- a/packages/shared/src/error-classifier.test.ts +++ b/packages/shared/src/error-classifier.test.ts @@ -157,4 +157,11 @@ describe("classifyError", () => { expect(result.category).toBe("auth"); expect(result.title).toBe("Authentication token expired"); }); + + it("classifies invalid API key error", () => { + const result = classifyError("API_KEY_INVALID error from Gemini API"); + expect(result.category).toBe("auth"); + expect(result.title).toBe("Invalid API key"); + expect(result.retryable).toBe(false); + }); }); diff --git a/packages/shared/src/error-classifier.ts b/packages/shared/src/error-classifier.ts index 4a8041e8..396c4470 100644 --- a/packages/shared/src/error-classifier.ts +++ b/packages/shared/src/error-classifier.ts @@ -234,6 +234,18 @@ const ERROR_PATTERNS: Array<{ retryable: true, }), }, + { + pattern: /API key not valid|API_KEY_INVALID/i, + classify: () => ({ + category: "auth", + title: "Invalid API key", + description: + "The provided API key is invalid. This can affect Gemini, Anthropic, or OpenAI depending on which agent was running.", + remedy: + "Go to Secrets and verify your API keys (GEMINI_API_KEY, ANTHROPIC_API_KEY, etc.) are valid and have not been revoked.", + retryable: false, + }), + }, { pattern: /exit code: (\d+)/i, classify: (match) => ({