hackmdio / hackmdio/api-client

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

Open
#51 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
19
Forks
8
PR merge metrics
No merged PRs in 30d

Description

## 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/

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.