FAILURE MAP
← Case archive

FA-27791 / HTTP ranges / Open access

A segment playlist resolves byte-range tags into per-segment Range values: a zero-byte sub-range cannot be expressed as an inclusive Range · case 01

A segment playlist resolves byte-range tags into per-segment Range values: a zero-byte sub-range cannot be expressed as an inclusive Range.

Verified by executionVariant 1 · 15 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The playlist-byterange-zero-length-subrange decision uses out=[] pending=None prev=None for raw in x: line=raw.strip() if not line: continue if line.startswith('#EXT-X-BYTERANGE:'): n,at,o=line[17:].partition('@') if not n.isdigit() or (at and not o.isdigit()): return None pending=[int(n),int(o) if at else None] elif line.startswith('#'): continue else: if pending is None: out.append([line,None]) prev=None else: n,o=pending if o is None: if prev is None or prev[0]!=line: return None o=prev[1] if n<0: return None out.append([line,'bytes=%d-%d'%(o,o+n-1)]) prev=[line,o+n] pending=None return out.

VERIFIED REPAIR

Apply the bounded decision exactly: out=[] pending=None prev=None for raw in x: line=raw.strip() if not line: continue if line.startswith('#EXT-X-BYTERANGE:'): n,at,o=line[17:].partition('@') if not n.isdigit() or (at and not o.isdigit()): return None pending=[int(n),int(o) if at else None] elif line.startswith('#'): continue else: if pending is None: out.append([line,None]) prev=None else: n,o=pending if o is None: if prev is None or prev[0]!=line: return None o=prev[1] if n==0: return None out.append([line,'bytes=%d-%d'%(o,o+n-1)]) prev=[line,o+n] pending=None return out

Unsuccessful approach: The partial repair uses out=[] pending=None prev=None for raw in x: line=raw.strip() if not line: continue if line.startswith('#EXT-X-BYTERANGE:'): n,at,o=line[17:].partition('@') if not n.isdigit() or (at and not o.isdigit()): return None pending=[int(n),int(o) if at else None] elif line.startswith('#'): continue else: if pending is None: out.append([line,None]) prev=None else: n,o=pending if o is None: if prev is None or prev[0]!=line: return None o=prev[1] if n==0 and not out: return None out.append([line,'bytes=%d-%d'%(o,o+n-1)]) prev=[line,o+n] pending=None return out, which still violates the stated contract.

Case contract

x is a list of playlist lines. Lines are trimmed; blank lines skipped; every other line starting with # is a tag or comment. #EXT-X-BYTERANGE:n[@o] (ASCII decimals) applies only to the next URI line. Without @o the range continues at the byte after the immediately previous segment, which must be a sub-range of the same URI string; otherwise null. A URI without a byte-range tag is a whole-resource segment [uri,null] and breaks any continuation chain. Zero-length sub-ranges and malformed tags return null. Return [uri,inclusive bytes=a-b or null] rows.

Why this case matters

Range responses combine representation identity, conditional requests, framing, and partial-object state.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    out=[]
    pending=None
    prev=None
    for raw in x:
        line=raw.strip()
        if not line: continue
        if line.startswith('#EXT-X-BYTERANGE:'):
            n,at,o=line[17:].partition('@')
            if not n.isdigit() or (at and not o.isdigit()): return None
            pending=[int(n),int(o) if at else None]
        elif line.startswith('#'):
            continue
        else:
            if pending is None:
                out.append([line,None])
                prev=None
            else:
                n,o=pending
                if o is None:
                    if prev is None or prev[0]!=line: return None
                    o=prev[1]
                if n<0: return None
                out.append([line,'bytes=%d-%d'%(o,o+n-1)])
                prev=[line,o+n]
            pending=None
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('zero-length-subrange fixture 0', json.loads(json.dumps(solve(['#EXTM3U','#EXTINF:1,','#EXT-X-BYTERANGE:100@0','a.ts','#EXTINF:1,','#EXT-X-BYTERANGE:50','a.ts','#EXTINF:1,','#EXT-X-BYTERANGE:25','a.ts']))), json.loads(json.dumps([['a.ts','bytes=0-99'],['a.ts','bytes=100-149'],['a.ts','bytes=150-174']])))
check('zero-length-subrange fixture 1', json.loads(json.dumps(solve(['#EXTM3U','# generated by tool','#EXT-X-BYTERANGE:10@5','b.ts']))), json.loads(json.dumps([['b.ts','bytes=5-14']])))
check('zero-length-subrange fixture 2', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts','#EXT-X-BYTERANGE:10','b.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 3', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts?v=1','#EXT-X-BYTERANGE:10','a.ts?v=2']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 4', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 5', json.loads(json.dumps(solve(['full.ts','#EXT-X-BYTERANGE:10','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 6', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts','a.ts','#EXT-X-BYTERANGE:10','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 7', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts','b.ts']))), json.loads(json.dumps([['a.ts','bytes=0-9'],['b.ts',None]])))
check('zero-length-subrange fixture 8', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:0@0','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 9', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:5@0','a.ts','#EXT-X-BYTERANGE:0','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 10', json.loads(json.dumps(solve(['#EXTM3U\r\n','#EXT-X-BYTERANGE:10@0\r\n','a.ts\r\n','#EXT-X-BYTERANGE:4\r\n','a.ts\r\n']))), json.loads(json.dumps([['a.ts','bytes=0-9'],['a.ts','bytes=10-13']])))
check('zero-length-subrange fixture 11', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:1x@0','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 12', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 13', json.loads(json.dumps(solve(['','#EXT-X-BYTERANGE:3@7','   ','c.ts']))), json.loads(json.dumps([['c.ts','bytes=7-9']])))
check('zero-length-subrange fixture 14', json.loads(json.dumps(solve(["#EXT-X-BYTERANGE:%d@0"%N,'a.ts',"#EXT-X-BYTERANGE:%d"%N,'a.ts']))), json.loads(json.dumps([['a.ts',"bytes=0-%d"%(N-1)],['a.ts',"bytes=%d-%d"%(N,2*N-1)]])))
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
zero-length-subrange fixture 0[['a.ts', 'bytes=0-99'], ['a.ts', 'bytes=100-149'], ['a.ts', 'bytes=150-174']][['a.ts', 'bytes=0-99'], ['a.ts', 'bytes=100-149'], ['a.ts', 'bytes=150-174']]Passed
zero-length-subrange fixture 1[['b.ts', 'bytes=5-14']][['b.ts', 'bytes=5-14']]Passed
zero-length-subrange fixture 2NoneNonePassed
zero-length-subrange fixture 3NoneNonePassed
zero-length-subrange fixture 4NoneNonePassed
zero-length-subrange fixture 5NoneNonePassed
zero-length-subrange fixture 6NoneNonePassed
zero-length-subrange fixture 7[['a.ts', 'bytes=0-9'], ['b.ts', None]][['a.ts', 'bytes=0-9'], ['b.ts', None]]Passed
zero-length-subrange fixture 8[['a.ts', 'bytes=0--1']]NoneFailed
zero-length-subrange fixture 9[['a.ts', 'bytes=0-4'], ['a.ts', 'bytes=5-4']]NoneFailed
zero-length-subrange fixture 10[['a.ts', 'bytes=0-9'], ['a.ts', 'bytes=10-13']][['a.ts', 'bytes=0-9'], ['a.ts', 'bytes=10-13']]Passed
zero-length-subrange fixture 11NoneNonePassed
zero-length-subrange fixture 12NoneNonePassed
zero-length-subrange fixture 13[['c.ts', 'bytes=7-9']][['c.ts', 'bytes=7-9']]Passed
zero-length-subrange fixture 14[['a.ts', 'bytes=0-0'], ['a.ts', 'bytes=1-1']][['a.ts', 'bytes=0-0'], ['a.ts', 'bytes=1-1']]Passed

SHA-256 / dfe993dc09c7c6a4d83746c751d1584fc9c2f1e325afcc6b23f77eac4264e6fb

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    out=[]
    pending=None
    prev=None
    for raw in x:
        line=raw.strip()
        if not line: continue
        if line.startswith('#EXT-X-BYTERANGE:'):
            n,at,o=line[17:].partition('@')
            if not n.isdigit() or (at and not o.isdigit()): return None
            pending=[int(n),int(o) if at else None]
        elif line.startswith('#'):
            continue
        else:
            if pending is None:
                out.append([line,None])
                prev=None
            else:
                n,o=pending
                if o is None:
                    if prev is None or prev[0]!=line: return None
                    o=prev[1]
                if n==0 and not out: return None
                out.append([line,'bytes=%d-%d'%(o,o+n-1)])
                prev=[line,o+n]
            pending=None
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('zero-length-subrange fixture 0', json.loads(json.dumps(solve(['#EXTM3U','#EXTINF:1,','#EXT-X-BYTERANGE:100@0','a.ts','#EXTINF:1,','#EXT-X-BYTERANGE:50','a.ts','#EXTINF:1,','#EXT-X-BYTERANGE:25','a.ts']))), json.loads(json.dumps([['a.ts','bytes=0-99'],['a.ts','bytes=100-149'],['a.ts','bytes=150-174']])))
check('zero-length-subrange fixture 1', json.loads(json.dumps(solve(['#EXTM3U','# generated by tool','#EXT-X-BYTERANGE:10@5','b.ts']))), json.loads(json.dumps([['b.ts','bytes=5-14']])))
check('zero-length-subrange fixture 2', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts','#EXT-X-BYTERANGE:10','b.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 3', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts?v=1','#EXT-X-BYTERANGE:10','a.ts?v=2']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 4', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 5', json.loads(json.dumps(solve(['full.ts','#EXT-X-BYTERANGE:10','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 6', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts','a.ts','#EXT-X-BYTERANGE:10','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 7', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts','b.ts']))), json.loads(json.dumps([['a.ts','bytes=0-9'],['b.ts',None]])))
check('zero-length-subrange fixture 8', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:0@0','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 9', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:5@0','a.ts','#EXT-X-BYTERANGE:0','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 10', json.loads(json.dumps(solve(['#EXTM3U\r\n','#EXT-X-BYTERANGE:10@0\r\n','a.ts\r\n','#EXT-X-BYTERANGE:4\r\n','a.ts\r\n']))), json.loads(json.dumps([['a.ts','bytes=0-9'],['a.ts','bytes=10-13']])))
check('zero-length-subrange fixture 11', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:1x@0','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 12', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 13', json.loads(json.dumps(solve(['','#EXT-X-BYTERANGE:3@7','   ','c.ts']))), json.loads(json.dumps([['c.ts','bytes=7-9']])))
check('zero-length-subrange fixture 14', json.loads(json.dumps(solve(["#EXT-X-BYTERANGE:%d@0"%N,'a.ts',"#EXT-X-BYTERANGE:%d"%N,'a.ts']))), json.loads(json.dumps([['a.ts',"bytes=0-%d"%(N-1)],['a.ts',"bytes=%d-%d"%(N,2*N-1)]])))
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
zero-length-subrange fixture 0[['a.ts', 'bytes=0-99'], ['a.ts', 'bytes=100-149'], ['a.ts', 'bytes=150-174']][['a.ts', 'bytes=0-99'], ['a.ts', 'bytes=100-149'], ['a.ts', 'bytes=150-174']]Passed
zero-length-subrange fixture 1[['b.ts', 'bytes=5-14']][['b.ts', 'bytes=5-14']]Passed
zero-length-subrange fixture 2NoneNonePassed
zero-length-subrange fixture 3NoneNonePassed
zero-length-subrange fixture 4NoneNonePassed
zero-length-subrange fixture 5NoneNonePassed
zero-length-subrange fixture 6NoneNonePassed
zero-length-subrange fixture 7[['a.ts', 'bytes=0-9'], ['b.ts', None]][['a.ts', 'bytes=0-9'], ['b.ts', None]]Passed
zero-length-subrange fixture 8NoneNonePassed
zero-length-subrange fixture 9[['a.ts', 'bytes=0-4'], ['a.ts', 'bytes=5-4']]NoneFailed
zero-length-subrange fixture 10[['a.ts', 'bytes=0-9'], ['a.ts', 'bytes=10-13']][['a.ts', 'bytes=0-9'], ['a.ts', 'bytes=10-13']]Passed
zero-length-subrange fixture 11NoneNonePassed
zero-length-subrange fixture 12NoneNonePassed
zero-length-subrange fixture 13[['c.ts', 'bytes=7-9']][['c.ts', 'bytes=7-9']]Passed
zero-length-subrange fixture 14[['a.ts', 'bytes=0-0'], ['a.ts', 'bytes=1-1']][['a.ts', 'bytes=0-0'], ['a.ts', 'bytes=1-1']]Passed

SHA-256 / 7742a18fc0dfa875e418a0f162dc0b3eb60eca862499a629d558ec1ff89ec485

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    out=[]
    pending=None
    prev=None
    for raw in x:
        line=raw.strip()
        if not line: continue
        if line.startswith('#EXT-X-BYTERANGE:'):
            n,at,o=line[17:].partition('@')
            if not n.isdigit() or (at and not o.isdigit()): return None
            pending=[int(n),int(o) if at else None]
        elif line.startswith('#'):
            continue
        else:
            if pending is None:
                out.append([line,None])
                prev=None
            else:
                n,o=pending
                if o is None:
                    if prev is None or prev[0]!=line: return None
                    o=prev[1]
                if n==0: return None
                out.append([line,'bytes=%d-%d'%(o,o+n-1)])
                prev=[line,o+n]
            pending=None
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('zero-length-subrange fixture 0', json.loads(json.dumps(solve(['#EXTM3U','#EXTINF:1,','#EXT-X-BYTERANGE:100@0','a.ts','#EXTINF:1,','#EXT-X-BYTERANGE:50','a.ts','#EXTINF:1,','#EXT-X-BYTERANGE:25','a.ts']))), json.loads(json.dumps([['a.ts','bytes=0-99'],['a.ts','bytes=100-149'],['a.ts','bytes=150-174']])))
check('zero-length-subrange fixture 1', json.loads(json.dumps(solve(['#EXTM3U','# generated by tool','#EXT-X-BYTERANGE:10@5','b.ts']))), json.loads(json.dumps([['b.ts','bytes=5-14']])))
check('zero-length-subrange fixture 2', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts','#EXT-X-BYTERANGE:10','b.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 3', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts?v=1','#EXT-X-BYTERANGE:10','a.ts?v=2']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 4', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 5', json.loads(json.dumps(solve(['full.ts','#EXT-X-BYTERANGE:10','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 6', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts','a.ts','#EXT-X-BYTERANGE:10','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 7', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@0','a.ts','b.ts']))), json.loads(json.dumps([['a.ts','bytes=0-9'],['b.ts',None]])))
check('zero-length-subrange fixture 8', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:0@0','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 9', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:5@0','a.ts','#EXT-X-BYTERANGE:0','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 10', json.loads(json.dumps(solve(['#EXTM3U\r\n','#EXT-X-BYTERANGE:10@0\r\n','a.ts\r\n','#EXT-X-BYTERANGE:4\r\n','a.ts\r\n']))), json.loads(json.dumps([['a.ts','bytes=0-9'],['a.ts','bytes=10-13']])))
check('zero-length-subrange fixture 11', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:1x@0','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 12', json.loads(json.dumps(solve(['#EXT-X-BYTERANGE:10@','a.ts']))), json.loads(json.dumps(None)))
check('zero-length-subrange fixture 13', json.loads(json.dumps(solve(['','#EXT-X-BYTERANGE:3@7','   ','c.ts']))), json.loads(json.dumps([['c.ts','bytes=7-9']])))
check('zero-length-subrange fixture 14', json.loads(json.dumps(solve(["#EXT-X-BYTERANGE:%d@0"%N,'a.ts',"#EXT-X-BYTERANGE:%d"%N,'a.ts']))), json.loads(json.dumps([['a.ts',"bytes=0-%d"%(N-1)],['a.ts',"bytes=%d-%d"%(N,2*N-1)]])))
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
zero-length-subrange fixture 0[['a.ts', 'bytes=0-99'], ['a.ts', 'bytes=100-149'], ['a.ts', 'bytes=150-174']][['a.ts', 'bytes=0-99'], ['a.ts', 'bytes=100-149'], ['a.ts', 'bytes=150-174']]Passed
zero-length-subrange fixture 1[['b.ts', 'bytes=5-14']][['b.ts', 'bytes=5-14']]Passed
zero-length-subrange fixture 2NoneNonePassed
zero-length-subrange fixture 3NoneNonePassed
zero-length-subrange fixture 4NoneNonePassed
zero-length-subrange fixture 5NoneNonePassed
zero-length-subrange fixture 6NoneNonePassed
zero-length-subrange fixture 7[['a.ts', 'bytes=0-9'], ['b.ts', None]][['a.ts', 'bytes=0-9'], ['b.ts', None]]Passed
zero-length-subrange fixture 8NoneNonePassed
zero-length-subrange fixture 9NoneNonePassed
zero-length-subrange fixture 10[['a.ts', 'bytes=0-9'], ['a.ts', 'bytes=10-13']][['a.ts', 'bytes=0-9'], ['a.ts', 'bytes=10-13']]Passed
zero-length-subrange fixture 11NoneNonePassed
zero-length-subrange fixture 12NoneNonePassed
zero-length-subrange fixture 13[['c.ts', 'bytes=7-9']][['c.ts', 'bytes=7-9']]Passed
zero-length-subrange fixture 14[['a.ts', 'bytes=0-0'], ['a.ts', 'bytes=1-1']][['a.ts', 'bytes=0-0'], ['a.ts', 'bytes=1-1']]Passed

SHA-256 / 14f333d926db294b1931ab77fda12cfc692775e13be4f53d05bf916cddf63851

Verification & scope

Deterministic simplified range service, with stipulated local policies and already parsed trusted inputs; not a complete HTTP implementation. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:41:28.258235+00:00.

Case digest / d6794afe8896600a4655a541eeb3fea0602bb05f701621bd1a2a990e874ca47b