Conversation
A 403 from Google means the Search Console API is not enabled in the Cloud project behind the OAuth client at least as often as it means a permission problem, and neither is fixable by reconnecting. Classifying it with 401 showed a healthy grant as "Connection expired" and hid the reason from the logs, so the only remedy the UI offers — remove the account and link it again — could never work. GSC now matches GA4: 401 and a token-mint failure prompt a reconnect, 403 surfaces as a load failure and stays reportable, and the 403 message names the Cloud console when Google reports accessNotConfigured or SERVICE_DISABLED. DataForSEO answers an unverified account with 403 and status_code 40104. As INTERNAL_ERROR that reached the user as "an unexpected error occurred" and let a local-SEO rank grid fire 24 more doomed, billable calls; it now joins 401 as DATAFORSEO_AUTH_FAILED, which GRID_ABORT_ERROR_CODES already aborts on. get_serp_results degrades per keyword rather than failing the batch, so its throws never reach the instrumentation wrapper and left no server-side trace of a provider outage or a billed-but-failed call. Those failures now warn before the tool degrades. Found while self-hosting: a disabled Search Console API cost an hour of disconnecting and reconnecting a grant that was healthy the whole time.
VodouAI
force-pushed
the
fix/error-classification
branch
from
September 20, 2026 06:26
ad817bb to
f64b191
Compare
TamerHammouda
pushed a commit
to TamerHammouda/open-seo
that referenced
this pull request
Sep 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three failures that told the operator the wrong thing, all found while self-hosting.
Search Console 403 read as a revoked grant
isExpectedGrantFailuregrouped 403 with 401, so any 403 rendered as "Connection expired" with a Reconnect button — and no log line, since expected grant failures are deliberately not reported.The most common 403 is the Search Console API not being enabled in the Cloud project behind
GOOGLE_CLIENT_ID. The grant is healthy, reconnecting changes nothing, and the UI's only suggested remedy is the one action that cannot work. On a fresh self-host this is an hour of deleting and re-linking an account that was fine the whole time, with nothing in the logs to say otherwise.403 now surfaces as a load failure and stays reportable, so the reason reaches the logs. This matches GA4, which already classified only 401 (
Ga4Service.requiresReconnect) — GSC was the outlier.messageForStatusalso splits 401 from 403 and names the Cloud console when Google reportsaccessNotConfiguredorSERVICE_DISABLED.DataForSEO 403 read as an internal error
An unverified DataForSEO account answers every call with 403 and
status_code: 40104, "Please verify your account before using the API." Only 401 mapped toDATAFORSEO_AUTH_FAILED, so this fell through toINTERNAL_ERRORand reached the user as "an unexpected error occurred."403 now joins 401. Beyond the message,
DATAFORSEO_AUTH_FAILEDis already inGRID_ABORT_ERROR_CODES, so a local-SEO rank grid aborts on the first failure instead of firing 24 more doomed, billable calls.get_serp_results failures left no trace
The tool degrades per keyword rather than failing the batch — good behavior — but the caught error never reaches the instrumentation wrapper, so nothing lands in the logs. A provider outage, an account-level rejection, or a call DataForSEO already billed is invisible server-side. I only found the 403s above because the agent's transcript mentioned them; the server had recorded nothing.
Failures now warn before the tool degrades. The degradation behavior is unchanged.
Notes
docs/SELF_HOSTING_GOOGLE_SEARCH_CONSOLE.mdgains a troubleshooting entry for this, including theGoogle account · <digits>symptom that appears when the email lookup fails alongside everything else.GscApiError(403)reconnect case is now the 401 case, plus one new test per invariant.src/server/features/gsc,src/server/lib/dataforseo, andsrc/server/mcp; prettier and oxlint clean.