Skip to content

fix(ENGKNOW-3981): refbases below position 1 returns N instead of throwing - #149

Open
gmagnu wants to merge 1 commit into
mainfrom
ENGKNOW-3981-gor-refbases-at-position-0-returns-n
Open

gmagnu wants to merge 1 commit into
mainfrom
ENGKNOW-3981-gor-refbases-at-position-0-returns-n

Conversation

@gmagnu

@gmagnu gmagnu commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Problem

refbases(chrom, pos1, pos2) (and refbases_with_build) fails the whole query with Index -1 out of bounds for length 10000 when pos1 is 0 and pos2 > 0, for example gorrow chr1,0 | calc r refbases(chrom,pos,pos+3). This can happen with rows that carry position 0, such as unmapped variants returned by liftover. refbase/single-base reads at position 0 already returned N.

Cause

In RefSeqFromChromSeq.getBases, the same-buffer check uses (pos - 1) / buffLength, which truncates toward zero, so position 0 maps to buffer 0. The fast path then indexes lastBuff(pos1 - offset - 1), i.e. lastBuff(-1). getBase catches the exception and returns N, but getBases does not.

Fix

Positions below 1 are treated like positions past the chromosome end: each reads as N and the result keeps length pos2 - pos1 + 1.

  • getBases emits N for pos1..min(pos2, 0) and continues from position 1, before any buffer lookup.
  • getBase returns N for pos < 1 up front instead of relying on the caught exception (which also avoids seeking to a negative offset for positions below -9999).

Positions >= 1 go through exactly the same code as before.

Tests

  • UTestRefSeqFromChromSeq.testGetRefbasesBelowPositionOne: getBases(chr17, 0, 4) = NAAGC (fresh and warm buffer), (-5, -1) = NNNNN, (0, 0) = N, getBase at 0 / -1 / -10001 = N, a range from -2 crossing the 10 kB buffer boundary, a range from more than one buffer below 1, and unchanged positive-position reads.
  • UTestGenomicFunctions.testRefBasesBelowPositionOne / testRefBasesWithBuildBelowPositionOne: gorrow chr17,0 | calc r refbases(...) / refbases_with_build(...) return NAAG.

The new tests failed before the fix with the index error. :model:test, :gortools:test pass.

Note

A separate pending change for refbases on contigs without sequence (ENGKNOW-3978) edits the same-buffer fast path in getBases and the buffer load in getBase. A trial merge shows RefSeqFromChromSeq.scala auto-merges (this PR only adds early returns at the top of both methods); UTestRefSeqFromChromSeq.java has a trivial conflict because both add a new test method at the same place. Keep both methods.

🤖 Generated with Claude Code

…owing

RefSeqFromChromSeq.getBases(chr, 0, n) took the same-buffer fast path,
because (pos - 1) / buffLength truncates toward zero for pos 0, and then
indexed lastBuff(-1), throwing ArrayIndexOutOfBoundsException. getBase
caught the error and returned 'N', so only multi-base reads failed, e.g.
refbases(chrom,pos,pos+3) on a row with pos 0.

Positions below 1 now read as 'N', like positions past the chromosome
end. getBases emits 'N' for pos1..min(pos2,0) and continues from
position 1; getBase returns 'N' for pos < 1 before any buffer lookup.
Positions >= 1 are unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

Junit Tests - Summary

4 912 tests  +3   4 741 ✅ +3   20m 39s ⏱️ - 1m 6s
  509 suites ±0     171 💤 ±0 
  509 files   ±0       0 ❌ ±0 

Results for commit db48da6. ± Comparison against base commit b79342b.

This branch has not been deployed

No deployments
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.

1 participant