{"record":{"id":"20320bb070ef144d","repo":"windmill-labs/windmill","slug":"body-error-res-statustext","errorCode":null,"errorMessage":"body.error || res.statusText","messagePattern":"body\\.error \\|\\| res\\.statusText","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/commands/app/devRecorder.ts","lineNumber":245,"sourceCode":"        ticker = null;\n        toggle.classList.remove('recording');\n        toggleLabel.textContent = 'Record';\n        downloadBtn.hidden = false;\n        setStatus(steps(recording.steps.length) + ' recorded');\n        // Only now: starting a fresh recording drops the one being uploaded.\n        await save();\n        toggle.disabled = false;\n      }\n\n      async function save() {\n        try {\n          var res = await fetch(config.savePath, {\n            method: 'POST',\n            headers: { 'Content-Type': 'application/json' },\n            body: JSON.stringify(recording)\n          });\n          var body = await res.json();\n          if (!res.ok) throw new Error(body.error || res.statusText);\n          setStatus(steps(recording.steps.length) + ' saved to ' + body.file);\n          if (config.playerBaseUrl) {\n            var src = window.location.origin + config.savePath + '/' + body.file;\n            openLink.href = config.playerBaseUrl + 'replay?src=' + encodeURIComponent(src);\n            openLink.hidden = false;\n          }\n        } catch (e) {\n          setStatus('Recorded, but saving failed: ' + (e && e.message ? e.message : e));\n        }\n      }\n\n      toggle.addEventListener('click', function () {\n        if (recorder.active) stop();\n        else start();\n      });\n\n      downloadBtn.addEventListener('click', function () {\n        if (recording) recorder.download(recording);","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/commands/app/devRecorder.ts#L227-L263","documentation":"Inside the app-dev recorder page served by `wmill app dev --recording`, saving a recording POSTs the recording JSON to the configured `savePath`. If the HTTP response is not ok, the thrown error message is the `error` field of the JSON body, falling back to the HTTP status text. It surfaces whatever error the dev-server save handler reported.","triggerScenarios":"The recording save endpoint returns a non-2xx response — e.g. the dev server failed to write the recording file to disk, the save path is misconfigured, or the server returned a JSON body with an `error` message (or no body, yielding statusText like 'Not Found' or 'Internal Server Error').","commonSituations":"Disk permission problems in the recording output directory; recorder save endpoint changed/moved between CLI versions; the dev server restarted and the page held a stale `savePath`; network hiccup during POST.","solutions":["Read the actual message: if it's a server-provided error, fix what the dev server reports (usually a file-write failure).","Check that the recording output directory exists and is writable by the `wmill app dev` process.","Reopen the recorder page / restart `wmill app dev --recording` to refresh the save endpoint config.","If statusText like 'Not Found' is shown, the savePath config is stale — restart the dev session."],"exampleFix":"var res = await fetch(config.savePath, { method: 'POST', ... });\nvar bodyText = await res.text();\nif (!res.ok) throw new Error('Failed to save recording: ' + (bodyText || res.statusText));","handlingStrategy":"try-catch","validationCode":"const res = await fetch(config.savePath, { method: 'HEAD' });\nif (!res.ok) throw new Error('Recorder save endpoint not available at ' + config.savePath);","typeGuard":"function isSaveOk(b: unknown): b is { file: string } { return typeof b === 'object' && b !== null && !('error' in b) && 'file' in b; }","tryCatchPattern":"try { await saveRecording(recording) } catch (e) { setStatus('save failed: ' + e.message + ' — check server logs / output dir permissions'); }","preventionTips":["Ensure the recording output directory exists and is writable","Restart the recorder page after restarting `wmill app dev`","Check the HTTP status and response body text, not just the thrown message"],"tags":["http","recording","dev-server","fetch"],"backgroundTag":"http-request-failed","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}