Skip to content

fix(api): return correct status codes for invalid and unreachable downloads - #5676

Merged
martinconic merged 2 commits into
masterfrom
fix/api-download-status-codes
Oct 28, 2026
Merged

martinconic merged 2 commits into
masterfrom
fix/api-download-status-codes

Conversation

@martinconic

@martinconic martinconic commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Checklist

  • I have read the coding guide.
  • My change requires a documentation update, and I have done it.
  • I have added tests to cover my changes.
  • I have added or updated fuzz targets for any code handling untrusted input.
  • I have filled out the description and linked the related issues.

Description

The new OpenAPI conformance check (#5673) found download requests that end in a 500 even though nothing is wrong with the node. This PR fixes those, plus a wrong content type on /pins/check.

1. Invalid addresses on /chunks and /bytes

Request Before After
GET /chunks/000…0 500 read chunk failed 400
GET /chunks/<any 64-byte address> 500 read chunk failed 400
HEAD /chunks/000…0 404 400, same as GET
GET/HEAD /bytes/000…0 503 after a network search (about 28 seconds) 400, immediately
GET/HEAD /bytes/<000…0 + decryption key> 503 after a network search 400, immediately

Retrieval already rejects an all-zero or wrong-length chunk address as invalid, but with a plain error the handlers couldn't recognize, so /chunks fell through to 500 and /bytes searched the network before giving up. The handlers now reject these upfront:

  • /chunks (GET and HEAD): the address must be 32 bytes and not all zeros (IsValidNonEmpty()), so both methods agree.
  • /bytes (GET and HEAD): a reference can also be 64 bytes (content address plus decryption key), so only its content address, the first 32 bytes, is checked for being all zeros.

Note that in bee the all-zero address is swarm.EmptyAddress (32 zero bytes), not swarm.ZeroAddress.

2. ACT downloads whose history can't be loaded

When a download carries ACT headers (Swarm-Act-Publisher and Swarm-Act-History-Address) and the history can't be fetched, the ACT middleware returned 500 act download failed. It only recognized the access control package's own errors, while a history that can't be retrieved fails with the usual storage and retrieval errors. These are now mapped the same way the regular download path already does it:

  • not found → 404 act or history entry not found
  • no usable peer → 503 act history could not be retrieved because no usable peer was available

This applies to every endpoint behind the ACT middleware (/bytes, /chunks, /bzz, …). Other errors still return 500.

3. /pins/check content type

The endpoint streams one JSON object per line (NDJSON) but declared Content-Type: application/json, so clients that parse the body as a single JSON document fail. It now sends application/x-ndjson. Neither bee-js nor swarm-cli calls this endpoint, so no known client is affected.

Tests

New unit tests for all three fixes: invalid addresses on /chunks and /bytes (GET and HEAD, including 64-byte references), the ACT error mapping on /bytes, /chunks and /bzz, and the /pins/check content type. Each one fails without its fix. To test the ACT errors, the access control mock got a WithDownloadError option. Existing tests that used the all-zero address as a "not found" example, or 3-byte chunk addresses, now use realistic 32-byte addresses.

I also checked all of the cases above against a testnet node built from this branch.

Open API Spec Version Changes (if applicable)

8.2.1 → 8.2.2

  • Added a shared 503 response, documented on GET /chunks/{address}, GET/HEAD /bytes/{address}, GET/HEAD /bzz/{address} and GET /bzz/{address}/{path}. These endpoints already returned 503 when no peer was available, but it wasn't documented.
  • /pins/check now documents application/x-ndjson.

#5674 bumps to the same 8.2.2, so whichever merges second keeps it. Once #5674 is merged, the /pins/check exclusion it adds to the Schemathesis run can be removed, since the content type is now correct.

Motivation and Context (Optional)

Part of #4974. These came out of the Schemathesis conformance run on the beekeeper cluster and on a testnet node.

Related Issue (Optional)

#4974, related to #5673 and #5674

AI Disclosure

  • This PR contains code that has been generated by an LLM.
  • I have reviewed the AI generated code thoroughly.
  • I possess the technical expertise to responsibly review the code generated in this PR.

…nloads

- reject the all-zero address on GET /chunks and GET and HEAD /bytes
  with 400 instead of a 500 or a slow 503 from the network lookup
- map ACT history lookups that fail with not found to 404 and with no
  usable peer to 503, instead of 500
- send application/x-ndjson as the content type of /pins/check, which
  streams one JSON object per line

Document the 503 response on the download endpoints and bump the API
version to 8.2.2.
Comment thread pkg/api/bytes.go Outdated
Comment thread pkg/api/bytes_test.go
Comment thread pkg/api/chunk.go Outdated
- check only the content address part of a /bytes reference, so an
  encrypted reference with an all-zero address is rejected too
- require a 32 byte, non-zero address on GET and HEAD /chunks, so
  both methods return 400 for the same invalid address
- use 32 byte addresses in the existing chunk tests
- keep the doc comment next to TestBytesGetHandlerNoPeers
@martinconic
martinconic merged commit 551c39d into master Oct 28, 2026
26 of 28 checks passed
@martinconic
martinconic deleted the fix/api-download-status-codes branch October 28, 2026 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants