danielmiessler/Fabric · error · Error
await response.text()
Error message
await response.text()
What it means
note-store's save throws the raw response body text when POST /notes responds non-OK: throw new Error(await response.text()). Unlike other clients there is no envelope parsing — whatever the server wrote (plain text, HTML error page, JSON string) becomes the Error message verbatim.
Source
Thrown at web/src/lib/store/note-store.ts:76
updated: ${frontmatter.updated}
author: ${frontmatter.author}
---
${content}`;
const response = await fetch('/notes', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
filename,
content: fileContent
})
});
if (!response.ok) {
throw new Error(await response.text());
}
return filename;
};
return {
subscribe,
updateContent: (content: string) => update(state => ({
...state,
content,
isDirty: true
})),
save: async () => {
const state = get({ subscribe });
const filename = await saveToFile(state.content);
update(state => ({
...state,View on GitHub (pinned to 338b89cfe9)
Solutions
- Look at the thrown message content: HTML usually means a proxy 404/413 page, JSON/plain text means the notes handler
- Sanitize the filename before saving (strip path separators, trim)
- Raise client_max_body_size on the proxy if large notes are rejected
- If 404 HTML appears, fix the proxy to forward /notes to the backend
Example fix
// before
if (!response.ok) {
throw new Error(await response.text());
}
// after
if (!response.ok) {
const body = await response.text();
let msg = body;
try { msg = JSON.parse(body).error || body; } catch {}
throw new Error(`Saving note failed (HTTP ${response.status}): ${msg.slice(0, 200)}`);
} Defensive patterns
Strategy: validation
Validate before calling
function isValidNoteFilename(f: string): boolean {
return /^[-\w. ]{1,120}$/.test(f) && !f.includes('..');
}
if (!isValidNoteFilename(filename)) throw new Error('Invalid note filename'); Type guard
function isNoteSaveFailure(e: unknown): boolean {
return e instanceof Error && /Saving note failed|^\s*<(!doctype|html)/i.test(e.message);
} Try / catch
try { await saveNote(filename, content); }
catch (e) {
const msg = e instanceof Error ? e.message : '';
if (/^\s*<(!doctype|html)/i.test(msg)) throw new Error('Notes backend unreachable (proxy 404/413)');
throw new Error(`Note save failed: ${msg.slice(0, 200)}`);
} Prevention
- Validate/trim filenames before POST /notes
- Detect HTML error pages in thrown text and translate to a clear message
- Confirm the proxy forwards /notes with adequate body limits
When it happens
Trigger: POST /notes with a filename the server rejects (invalid chars, too long), body too large for the proxy, or server IO failure writing the note file.
Common situations: Filename containing '/' or '..'; nginx default 1MB body limit rejecting large notes; backend route /notes (no /api prefix) not proxied in dev, returning the dev server's 404 HTML as the error message.
Related errors
- HTTP error! status: ${response.status}
- HTTP_ERROR
- errorData.error || `HTTP error! status: ${response.status}`
- Fabric API error: ${fabricResponse.statusText}
- response.error
AI-assisted analysis of danielmiessler/Fabric@338b89cfe9 (2026-08-15).
Data as JSON: /api/errors/7d528cf884b1aa3d.
Report an issue: GitHub.