Three days after I published a post about hitting a wrong-account bug in my own Search Console integration, a stranger left a comment pointing out a second, deeper version of the same problem I hadn't noticed yet. Not a typo fix, not a "nice post" -- a specific, correct critique of the actual architecture of my error handling, from someone I'd never interacted with before. This is the first time in this whole project that "build in public" has produced something back.
What showed up in the comments
The comment came from a developer identifying himself as ten-plus years into a career, on the post about the Search Console wrong-account mixup. The core of it was one line: "OAuth debugging is often an identity problem before it becomes an API problem." Underneath that framing were four concrete suggestions -- log the authorized account identity, token metadata, granted scopes, and expiration separately from application config; call sites.list before querying to confirm the expected property actually exists for the authenticated account; add structured error classification and exponential backoff for 401/403/429/5xx; and build a small adapter layer to normalize date-range formats across Google APIs.
None of it was vague. Every suggestion mapped to something specific enough that I could tell this person had actually read the post carefully, not skimmed it for a place to leave a generic comment.
Taking it seriously without taking it whole
The instinct when a stranger with more stated experience gives you a list of "you should do X" is to just do all of X. I didn't, and I think that instinct -- resisting wholesale adoption -- was the actually useful part of this exercise. Two of the four suggestions were clearly worth doing. Two weren't, for this project specifically, and the reasoning for each split matters more than the split itself.
Worth doing: identity and token logging, plus a pre-flight resource check. This wasn't a hypothetical improvement -- it was a direct fix for a bug class I'd already been burned by three separate times on this exact project (Blogger, Search Console, and Google Analytics all silently authenticated as the wrong Google account at different points). Printing which account a token belongs to, and which resources it can actually see, before running a real query, converts a confusing 403 into an immediate, readable answer. Cheap to add, directly addressed a real recurring failure.
Not worth doing, for now: retry/backoff and a date-format adapter layer. Exponential backoff and structured error classification are the right call for a service under real traffic, handling requests from users who notice when something silently fails. This is a script I run myself, by hand or on a timer, a handful of times a day. If a call fails, I see it immediately and rerun it -- there's no queue of angry users behind a failed request. Building retry infrastructure for that is solving a problem I don't have yet. Same logic for the date adapter: I've hit exactly one date-format mismatch across three separate Google API integrations so far. One occurrence doesn't justify an abstraction layer; the actual fix was two lines of datetime math, and the next time it happens (if it happens again) I'll fix it the same way.
What I actually shipped
Same afternoon, I added a small identity-check function to each of the three scripts that authenticate against Google APIs -- Blogger, Search Console, and Analytics. Each one now prints the token's expiration and granted scopes, then does a lightweight pre-flight lookup (which blogs this account manages, which sites it can query, which GA4 properties it can see) before running anything real. If the expected resource isn't in that list, the script says so immediately instead of failing three steps later with an opaque permission error. Here's the actual function, from the Search Console script:
def print_identity(creds, service) -> None:
print(f"[인증 확인] 토큰 만료: {creds.expiry} / 권한 범위: {creds.scopes}")
try:
sites = service.sites().list().execute()
urls = [s["siteUrl"] for s in sites.get("siteEntry", [])]
except Exception:
urls = []
if SITE_URL.rstrip("/") in [u.rstrip("/") for u in urls]:
print(f"[인증 확인] 대상 사이트 접근 가능 확인됨: {SITE_URL}")
else:
print(f"[인증 확인] 경고: 이 계정에서 접근 가능한 사이트 목록에 {SITE_URL}이 없음 -- 계정 확인 필요")
print(f"[인증 확인] 접근 가능한 사이트: {urls}")
The Blogger and Analytics versions follow the same shape, adapted to whatever "list the resources this token can see" call each API exposes. Nine lines of code, and every account mixup since has surfaced as a printed warning before the real query even runs, instead of three steps later as a bare 403.
Replying in kind
I wrote a reply back in roughly the same register the comment arrived in -- short declarative sentences, specific about what changed, specific about what didn't and why, no filler thanking language stacked on top. It felt like the right way to close the loop: not just accepting the feedback, but showing the actual reasoning for the parts I kept and the parts I set aside, the same way the original comment showed its reasoning rather than just listing opinions.
Why this is the post I most wanted to write
Every other post in this series has been me finding my own bugs and writing them up afterward. This is the first time someone outside the project found something in it, said so specifically enough to be useful, and the result was a real commit rather than a vague "thanks for the feedback." That's the actual mechanism "build in public" is supposed to run on, and until this week it had only ever been theoretical for this blog.
Top comments (0)