{"record":{"id":"2239f42b46fe30c9","repo":"antiwork/gumroad","slug":"dropped-a-non-inertia-response-to-a-background-con","errorCode":null,"errorMessage":"Dropped a non-Inertia response to a background content-page poll of ${redactUrlForLogging(requestedUrl)} (path redacted on purpose — it is not safe to share). Something between the browser and Gumroad answered the poll with its own page (an edge challenge, a proxy error, a captive portal). The page keeps what it already loaded and the poll keeps retrying; further drops for this page are not logged.","messagePattern":"Dropped a non-Inertia response to a background content-page poll of (.+?) \\(path redacted on purpose — it is not safe to share\\)\\. Something between the browser and Gumroad answered the poll with its own page \\(an edge challenge, a proxy error, a captive portal\\)\\. The page keeps what it already loaded and the poll keeps retrying; further drops for this page are not logged\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/javascript/utils/inertia_partial_reload.ts","lineNumber":170,"sourceCode":"/**\n * Warns once per URL that a background poll response was dropped. Safe to call on every drop.\n * The warning names only the redacted path shape — never the content token or query string.\n *\n * `response` is the same axios response passed to `isUnredirectedDownloadPagePollResponse`.\n */\nexport const warnAboutDroppedPollResponse = (response: unknown): void => {\n  if (!isRecord(response)) return;\n  const { config, request } = response;\n\n  // Prefer the URL the browser actually ended on; fall back to the one the request asked for.\n  const requestedUrl =\n    (isRecord(request) ? stringOrNull(request.responseURL) : null) ??\n    (isRecord(config) ? stringOrNull(config.url) : null);\n  if (requestedUrl === null || alreadyWarnedUrls.has(requestedUrl)) return;\n\n  alreadyWarnedUrls.add(requestedUrl);\n  // eslint-disable-next-line no-console\n  console.warn(\n    `Dropped a non-Inertia response to a background content-page poll of ${redactUrlForLogging(requestedUrl)} (path redacted on purpose — it is not safe to share). Something between the browser and Gumroad answered the poll with its own page (an edge challenge, a proxy error, a captive portal). The page keeps what it already loaded and the poll keeps retrying; further drops for this page are not logged.`,\n  );\n};\n","sourceCodeStart":152,"sourceCodeEnd":174,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/javascript/utils/inertia_partial_reload.ts#L152-L174","documentation":"Not a thrown error — a one-time-per-URL console breadcrumb from warnAboutDroppedPollResponse. The buyer content page's background poll (an Inertia partial reload of audio_durations / latest_media_locations, every few seconds) received a non-Inertia response (no X-Inertia header) from the same URL it requested; the guard decided to drop it instead of navigating, so the page keeps its state and the poll retries. The logged path is redacted to /d/[redacted] because the /d/:token URL is itself the access credential and the warning is expected to be pasted into support tickets.","triggerScenarios":"A network middlebox answers the poll with its own HTML while the buyer is on a /d/:token content page: cloudflare-style edge challenge, ISP or captive-portal interception, corporate proxy error page, or an injected gateway login. The URL is deliberately not safe to print because the token grants file access.","commonSituations":"Buyers on hotel/airport wifi behind captive portals, VPNs with TLS inspection, regions with DNS-level interception, or transient CDN 502/503 HTML pages during incidents.","solutions":["Treat it as network interception, not an app bug: ask the buyer to switch networks or retry after leaving the captive portal; the poll self-heals when interception ends.","If reproducible on a clean network, capture the actual response body/status in devtools to identify which middlebox is answering.","No page code change is needed — dropping and retrying is the designed recovery; the warning exists only as a diagnostic breadcrumb."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"import { isUnredirectedDownloadPagePollResponse, warnAboutDroppedPollResponse } from \"@/utils/inertia_partial_reload\";\n\n// In the Inertia \"invalid\" response handler, before navigating:\nif (isUnredirectedDownloadPagePollResponse(response)) {\n  warnAboutDroppedPollResponse(response); // one-time, redacted breadcrumb\n  return; // keep page state; the poll retries on its timer\n}\n// otherwise navigate as Inertia does by default","typeGuard":"// Narrows an unknown axios response to a droppable download-page poll\nconst isUnredirectedDownloadPagePollResponse = (response: unknown): boolean => {\n  if (!isRecord(response)) return false;\n  const { config } = response;\n  if (!isRecord(config)) return false;\n  return isGet(config) && isDownloadPagePoll(config) && !wasRedirected(config, (response as { request?: unknown }).request);\n};","tryCatchPattern":null,"preventionTips":["Never navigate on a same-URL non-Inertia poll response — navigating re-issues the intercepted request and loses the buyer's session progress.","Log only redacted URL shapes from buyer pages; /d/:token URLs are credentials and end up pasted into support tickets.","Warn once per URL per page load; per-poll logging buries the console and leaks nothing extra."],"tags":["inertia","polling","network-interception","frontend","console","captive-portal"],"backgroundTag":"proxy-intercepted-response","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}