From c8a1e1735925d38cebcf092cff791ad1b2fed100 Mon Sep 17 00:00:00 2001 From: mattmacrocket Date: Thu, 2 Jul 2026 16:38:13 -0500 Subject: [PATCH] fix: surface DataForSEO auth failures as an actionable error instead of "unexpected error" (#53) --- src/client/lib/error-messages.ts | 2 ++ src/server/lib/dataforseo/core.ts | 4 +++- src/server/lib/dataforseoAccountState.ts | 8 ++++++++ src/shared/error-codes.ts | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/client/lib/error-messages.ts b/src/client/lib/error-messages.ts index 4ce44fa..5486409 100644 --- a/src/client/lib/error-messages.ts +++ b/src/client/lib/error-messages.ts @@ -22,6 +22,8 @@ const STANDARD_MESSAGES: Record = { "AI Optimization is not enabled for the connected DataForSEO account yet.", AI_SEARCH_BILLING_ISSUE: "The connected DataForSEO account has a billing or balance issue.", + DATAFORSEO_AUTH_FAILED: + "DataForSEO rejected the API key. Check that DATAFORSEO_API_KEY is the base64 of your DataForSEO login:password.", RATE_LIMITED: "Too many requests. Please wait and try again.", UPSTREAM_UNAVAILABLE: "The data provider is temporarily unavailable. Please retry in a moment.", diff --git a/src/server/lib/dataforseo/core.ts b/src/server/lib/dataforseo/core.ts index 493bf9c..221016a 100644 --- a/src/server/lib/dataforseo/core.ts +++ b/src/server/lib/dataforseo/core.ts @@ -96,7 +96,9 @@ function createAuthenticatedFetch(classify?: DataforseoErrorClassifier) { ? "UPSTREAM_UNAVAILABLE" : response.status === 429 ? "RATE_LIMITED" - : "INTERNAL_ERROR"; + : response.status === 401 + ? "DATAFORSEO_AUTH_FAILED" + : "INTERNAL_ERROR"; const error = new AppError( code, `DataForSEO HTTP ${response.status} on ${path}`, diff --git a/src/server/lib/dataforseoAccountState.ts b/src/server/lib/dataforseoAccountState.ts index 71461d3..699ae49 100644 --- a/src/server/lib/dataforseoAccountState.ts +++ b/src/server/lib/dataforseoAccountState.ts @@ -58,6 +58,14 @@ export async function fetchDataforseoAccountState(): Promise