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

  1. Look at the thrown message content: HTML usually means a proxy 404/413 page, JSON/plain text means the notes handler
  2. Sanitize the filename before saving (strip path separators, trim)
  3. Raise client_max_body_size on the proxy if large notes are rejected
  4. 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

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


AI-assisted analysis of danielmiessler/Fabric@338b89cfe9 (2026-08-15). Data as JSON: /api/errors/7d528cf884b1aa3d. Report an issue: GitHub.