hackmdio / hackmdio/api-client
PATCH /notes/:noteId intermittently returns 500 after ~6 seconds with no body detail
- Vorherrschende Sprache
- TypeScript
- Sterne
- 19
- Forks
- 8
- PR-Merge-Kennzahlen
- Keine gemergten PRs in 30 T.
Beschreibung
## 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/
```
## Request details
| Field | Value |
|-------|-------|
| Method | `PATCH` |
| Content-Type | `application/json` |
| Authorization | `Bearer ` (valid, same token works immediately after) |
| Body | `{ "content": "" }` |
| 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
- You can test it on this repo https://github.com/Arigatouz/ali-productive-board where i use HackMD like. DB
- Here is a live version of it https://arigatouz.github.io/ali-productive-board/
Beitragsleitfaden
Für dieses Repository ist kein Beitragsleitfaden indexiert
Rechercherichtung
Start with the PATCH /v1/notes/:noteId request path and reproduce the intermittent failure using the timing and retry pattern described. Trace the request through the API client and backend boundary, then use the response status, delay, and storage-layer behavior to identify the failure; done means a confirmed cause and an appropriate stable error response or documented fix.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- typescript
- Bereich
- api, backend
- Issue-Typ
- Bug
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Ruhig
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 45/100