Skip to content

fix: refget endpoint reported an incorrect Content-Length, leading to RuntimeErrors - #847

Open
bencap wants to merge 2 commits into
release-2026.3.0from
bugfix/bencap/846/refget-content-length-for-subsequence-requests
Open

fix: refget endpoint reported an incorrect Content-Length, leading to RuntimeErrors#847
bencap wants to merge 2 commits into
release-2026.3.0from
bugfix/bencap/846/refget-content-length-for-subsequence-requests

Conversation

@bencap

@bencap bencap commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

The refget sequence endpoint declared Content-Length as the full length of the sequence on every response, including subsequence requests. NC_000016.10?start=2077608&end=2085800 streamed 8,192 bytes under a declared 90,338,345, and the ASGI server aborted the response with RuntimeError: Response content shorter than Content-Length after the status line was already committed. Clients got a truncated body.

Both sequence endpoints now resolve start/end to concrete half-open bounds once the sequence length is known, and derive validation, headers, and the streamed body from those same values.

Changes

  • refget: Content-Length reports the bytes actually streamed. Bounds validation runs whenever either bound is supplied, not only when both are. A one-sided out-of-range request previously skipped validation entirely and returned an empty 200 carrying the full sequence length.
  • seqrepo: same one-sided bounds check. This endpoint never set Content-Length and so could not crash, but returned a truncated body under a 200 for coordinates past the end of a sequence.
  • tests: every request shape asserts Content-Length == len(body); added coverage for service-info and the range/query-param conflict; sharpened the unit/integration marker definitions.

Behavior changes

Requests that were broken and now work:

Request Before After
refget subsequence, client not accepting gzip truncated body, RuntimeError server-side 200/206 with correct Content-Length
refget one-sided bound within range (?start=1, ?end=3) correct bytes under a full-length Content-Length correct bytes and header

Requests that were silently wrong and are now rejected:

Request Before After
refget, one-sided bound out of range empty 200 416 with Content-Range
seqrepo, coordinates past end of sequence truncated/empty 200 422
seqrepo, negative start passed through to seqrepo 422

Note

GZipMiddleware strips Content-Length from compressed responses, and TestClient requests gzip by default. That is why this reached production with the endpoint under test, and why the new assertions pin Accept-Encoding: identity. Without that header they pass regardless of the fix.

bencap added 2 commits August 17, 2026 11:57
The refget sequence endpoint set Content-Length to the length of the
whole sequence on every response, including subsequence requests. A
request for NC_000016.10?start=2077608&end=2085800 streamed 8192 bytes
under a declared 90338345, and the ASGI server aborted the response with
"Response content shorter than Content-Length" once the status line was
already committed. GZipMiddleware strips Content-Length from compressed
responses, so only clients requesting identity encoding were affected,
and TestClient's default gzip request meant no existing test could
observe the header.

- Resolve start/end to concrete half-open bounds as soon as the sequence
  length is known, and derive validation, Content-Length, Content-Range,
  and the generator bounds from those same values
- Run bounds validation whenever either bound is supplied, not only when
  both are; a one-sided out-of-range request previously skipped
  validation and returned an empty 200 carrying the full sequence length
- Apply the same one-sided bounds check to the seqrepo sequence
  endpoint, which never set Content-Length and so could not crash, but
  returned a truncated body under a 200 for coordinates past the end of
  the sequence. It now rejects them with 422, the code that endpoint
  already used for start > end
- Cover every request shape with tests asserting Content-Length equals
  the returned body length, pinning Accept-Encoding: identity so gzip
  cannot mask a regression

Closes #846
…erage

Tighten the marker definitions so the distinction is about mocking and
scope rather than a vague notion of size, and mark the refget and
seqrepo router suites accordingly.

- Redefine `integration` as an end-to-end multi-component flow with no
  internal mocking, and `unit` as fast and isolated, explicitly allowing
  real collaborators when they are local, fast, and deterministic
- Mark tests/routers/test_refget.py and tests/routers/test_seqrepo.py as
  unit suites
- Cover the refget service-info endpoint, including the
  HGVS_SEQREPO_DIR-derived data version and its "unknown" fallback
- Cover the 400 returned when start/end query parameters are combined
  with a Range header
@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 32058748293

Warning

No base build found for commit 95a2917 on release-2026.2.8.
Coverage changes can't be calculated without a base build.
If a base build is processing, this comment will update automatically when it completes.

Coverage: 89.066%

Details

  • Patch coverage: 22 of 22 lines across 2 files are fully covered (100%).

Uncovered Changes

No uncovered changes found.

Coverage Regressions

Requires a base build to compare against. How to fix this →


Coverage Stats

Coverage Status
Relevant Lines: 14350
Covered Lines: 12781
Line Coverage: 89.07%
Coverage Strength: 0.89 hits per line

💛 - Coveralls

@bencap
bencap changed the base branch from release-2026.2.8 to release-2026.3.0 August 18, 2026 22:12
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.

Refget sequence endpoint declares the full sequence length as Content-Length on subsequence requests

2 participants