Skip to content

PATCH /notes/:noteId intermittently returns 500 after ~6 seconds with no body detail #51

@Arigatouz

Description

@Arigatouz

Summary

Calls to PATCH /v1/notes/:noteId intermittently return HTTP 500 with the body {"error":"Failed to update note"}. The failure is not deterministic — the exact same request succeeds when retried 1–2 seconds later. The issue resolves itself within a minute.

Endpoint

PATCH https://api.hackmd.io/v1/notes/<note-id>

Request details

Field Value
Method PATCH
Content-Type application/json
Authorization Bearer <token> (valid, same token works immediately after)
Body { "content": "<markdown string ~400 bytes>" }
Protocol HTTP/3
TLS TLSv1.3

Observed response

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{"error":"Failed to update note"}

Timing evidence

From Cloudflare Worker logs (the request is routed through a Cloudflare Worker CORS proxy before reaching the HackMD API):

Metric Value
Worker CPU time ~0 ms (proxy only, no compute)
Wall time (total round-trip) ~6,072 ms
Worker outcome ok (worker completed normally)
Response status received from HackMD 500

The 6-second wall time indicates the HackMD backend held the connection open before returning the 500 — this is not a timeout on the client side.

Reproduction pattern

  • Frequency: Occasional, roughly 1 in 20–30 PATCH calls during normal use
  • Recovery: Retrying the identical request 1.5–2 seconds later succeeds
  • The note content is valid markdown (plain text, checkboxes, headings)
  • The note is owned by the authenticated user — no permission issues

What is NOT the cause

  • ❌ Invalid token — the same token succeeds immediately on retry
  • ❌ Permission / ownership — same note, same token works after retry
  • ❌ Malformed body — same payload succeeds on retry
  • ❌ Client-side timeout — the server held the connection for 6 seconds before responding 500
  • ❌ CORS proxy issue — the proxy passes the request and response through transparently; its own outcome is ok
  • ❌ Rate limiting — there is no burst of requests, this happens on isolated single saves

Impact

Users see a "Save failed" error and must manually retry. With a client-side retry in place the error is hidden, but the underlying instability means saves are silently slower and occasionally double-charged against any rate limits.

Request

  1. Investigate whether the backend experiences transient write failures on the note storage layer
  2. If a 500 is unavoidable, consider returning a 503 Service Unavailable with a Retry-After header so clients can back off intelligently
  3. A more descriptive error body (e.g. the underlying cause) would help distinguish storage errors from permission or validation errors

Environment

  • API version: v1
  • Client: browser (Chrome 145, macOS)
  • Region inferred from Cloudflare colo: MRS (Marseille edge, request origin: Egypt)

Test

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions