{"record":{"id":"6b424d2da3253033","repo":"Freika/dawarich","slug":"onboarding-failed-to-persist-completion","errorCode":null,"errorMessage":"[Onboarding] Failed to persist completion:","messagePattern":"\\[Onboarding\\] Failed to persist completion:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/javascript/controllers/onboarding_modal_controller.js","lineNumber":199,"sourceCode":"          screen !== targetName,\n        )\n      }\n    }\n  }\n\n  completeOnboarding() {\n    this.trackEvent(\"onboarding_completed\")\n\n    if (this.onboardingUrlValue) {\n      fetch(this.onboardingUrlValue, {\n        method: \"PATCH\",\n        headers: {\n          \"X-CSRF-Token\": document.querySelector('meta[name=\"csrf-token\"]')\n            ?.content,\n          \"Content-Type\": \"application/json\",\n        },\n      }).catch((error) => {\n        console.warn(\"[Onboarding] Failed to persist completion:\", error)\n      })\n    }\n  }\n\n  trackEvent(eventName) {\n    if (typeof window.sa_event === \"function\") {\n      window.sa_event(eventName)\n    }\n  }\n}\n","sourceCodeStart":181,"sourceCodeEnd":210,"githubUrl":"https://github.com/Freika/dawarich/blob/97fad417c5a11b0eb11157890635e015723a2e97/app/javascript/controllers/onboarding_modal_controller.js#L181-L210","documentation":"The onboarding modal fires a PATCH to onboardingUrlValue to record that the user finished onboarding, guarded only by .catch. fetch only rejects on network-level failures (offline, DNS, aborted request), so HTTP 4xx/5xx statuses pass silently and do NOT produce this message. When it does fire, the analytics event has already been tracked but the server still considers onboarding unfinished, so the modal can reappear next visit.","triggerScenarios":"User goes offline or the tab suspends as the modal closes; server or DNS unreachable; the request aborted by Turbo navigation replacing the page; a missing csrf-token meta tag yields a 422 that is a silent failure, not this catch; onboardingUrlValue pointing at a nonexistent route.","commonSituations":"Mobile Safari suspending the tab on modal dismissal; Rails layout skipping csrf_meta_tags so the X-CSRF-Token header is blank; reverse proxy 502 during deploys; staging URLs left in a copied template.","solutions":["Check the Network tab: a PATCH showing a 4xx/5xx status did NOT trigger this catch — handle response.ok separately","Ensure the layout renders csrf_meta_tags so the X-CSRF-Token header is valid","Add an explicit response.ok check and a single retry so transient failures still persist completion","If the modal keeps reappearing, confirm the PATCH reached the server in Rails logs"],"exampleFix":"// before\nfetch(this.onboardingUrlValue, { method: \"PATCH\", headers })\n  .catch((error) => {\n    console.warn(\"[Onboarding] Failed to persist completion:\", error)\n  })\n// after\ntry {\n  const res = await fetch(this.onboardingUrlValue, { method: \"PATCH\", headers, keepalive: true })\n  if (!res.ok) console.warn(\"[Onboarding] Persist returned HTTP\", res.status)\n} catch (error) {\n  console.warn(\"[Onboarding] Failed to persist completion:\", error)\n  fetch(this.onboardingUrlValue, { method: \"PATCH\", headers, keepalive: true }).catch(() => {}) // one retry\n}","handlingStrategy":"retry","validationCode":"const token = document.querySelector('meta[name=\"csrf-token\"]')?.content\nif (!this.onboardingUrlValue || !token) {\n  console.warn(\"[Onboarding] Missing URL or CSRF token; skipping persist\")\n  return\n}","typeGuard":null,"tryCatchPattern":"try {\n  const res = await fetch(this.onboardingUrlValue, { method: \"PATCH\", headers, keepalive: true })\n  if (!res.ok) throw new Error(`HTTP ${res.status}`)\n} catch (error) {\n  console.warn(\"[Onboarding] Failed to persist completion:\", error)\n  fetch(this.onboardingUrlValue, { method: \"PATCH\", headers, keepalive: true }).catch(() => {})\n}","preventionTips":["Always pair fetch .catch with an explicit response.ok check — fetch only rejects on network failure","Use keepalive: true for fire-and-forget persistence that must survive page navigation","Verify csrf_meta_tags is present in every layout that renders the modal"],"tags":["fetch","dawarich","onboarding","csrf","network"],"backgroundTag":"fetch-network-error","analyzedSha":"97fad417c5a11b0eb11157890635e015723a2e97","analyzedAt":"2026-08-21T17:04:17.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}