{"record":{"id":"9488b40282966ee6","repo":"antiwork/gumroad","slug":"the-banner-could-not-be-hidden-check-your-connect","errorCode":null,"errorMessage":"The banner could not be hidden. Check your connection and try again.","messagePattern":"The banner could not be hidden\\. Check your connection and try again\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"app/javascript/components/DashboardPage.tsx","lineNumber":366,"sourceCode":"  const dismissGettingStarted = async () => {\n    setGettingStartedDismissed(true);\n    await request({\n      method: \"POST\",\n      url: Routes.dashboard_dismiss_getting_started_checklist_path(),\n      accept: \"json\",\n    });\n  };\n\n  const [gumheadDismissed, setGumheadDismissed] = React.useState<boolean>(false);\n  const dismissGumhead = async () => {\n    setGumheadDismissed(true);\n    try {\n      const response = await request({\n        method: \"POST\",\n        url: Routes.dashboard_dismiss_gumhead_promo_path(),\n        accept: \"json\",\n      });\n      if (!response.ok) throw new Error();\n    } catch {\n      setGumheadDismissed(false);\n      showAlert(\"The banner could not be hidden. Check your connection and try again.\", \"error\");\n    }\n  };\n\n  return (\n    <div>\n      <PageHeader\n        title=\"Dashboard\"\n        actions={\n          <>\n            {tax_center_enabled\n              ? null\n              : Object.keys(tax_forms).length > 0 && <DownloadTaxFormsPopover taxForms={tax_forms} />}\n            {/* \"accent\" is the design system's highlight color (Gumroad pink by default) — the\n                same style as the New product button on the Products page. Hidden for team\n                members whose role can't create products. */}","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/javascript/components/DashboardPage.tsx#L348-L384","documentation":"dismissGumhead hides the dashboard promo banner optimistically (setGumheadDismissed(true)), then POSTs to dashboard_dismiss_gumhead_promo_path. If the response is not ok — or the fetch throws — the catch rolls the banner back and shows 'The banner could not not be hidden...' (fixed string). This is the optimistic-UI-rollback pattern: state change applied immediately, reverted on failure.","triggerScenarios":"POST to the dismiss endpoint returning 401 (session expired), 403 (CSRF token stale after re-login in another tab), or 404 after a route change; or a network failure — all land in the same bare catch and roll the banner back.","commonSituations":"Dashboard tab left open for days until the session cookie expires; seller re-logged-in in another tab so the CSRF token embedded in the page no longer matches the session; flaky mobile connection dismissing the banner on the train.","solutions":["Check the Network tab for the dismiss POST's status — 401 vs 403 vs network failure each have different fixes.","If 401/CSRF, reload the dashboard; the fresh page carries a valid token and dismissing works.","If it persists, check server logs for the dismiss action (route present, controller not raising).","If network flakiness is common, consider retrying once before rolling back the optimistic state."],"exampleFix":"// before\n} catch {\n  setGumheadDismissed(false);\n  showAlert('The banner could not be hidden. Check your connection and try again.', 'error');\n}\n\n// after — keep the rollback, but name the likely cause\n} catch (e) {\n  assertResponseError(e);\n  setGumheadDismissed(false);\n  showAlert('The banner could not be hidden. Your session may have expired — reload the page and try again.', 'error');\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":"const isResponseError = (e: unknown): e is ResponseError => e instanceof ResponseError;","tryCatchPattern":"setGumheadDismissed(true); // optimistic\ntry {\n  const response = await request({ method: 'POST', url: Routes.dashboard_dismiss_gumhead_promo_path(), accept: 'json' });\n  if (!response.ok) throw new ResponseError();\n} catch (e) {\n  assertResponseError(e);\n  setGumheadDismissed(false); // rollback keeps UI truthful\n  showAlert('The banner could not be hidden. Check your connection and try again.', 'error');\n}","preventionTips":["Always pair the optimistic setState with a rollback in the catch — the pattern's whole value is the recovery path.","For low-stakes writes like dismissal, consider fire-and-forget plus one silent retry instead of a user-facing error.","A 401 on this POST almost always means the page's session/token went stale — suggest a reload in the message.","Do not leave the banner hidden on failure; the server will re-serve it and the two states will fight."],"tags":["http","optimistic-ui","dashboard","rollback","banner-dismiss"],"backgroundTag":"http-request-failed","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}