Summary
BundleBytesComposed (composed bundling) panics with runtime error: index out of range [N] with length N when the document contains a $ref that resolves to an array (sequence) node with an odd number of elements. A top-level tags: {$ref: tags.yaml#/tags} pointing at an odd-length tag list reproduces it reliably.
- libopenapi: v0.37.2 (hit via
vacuum v0.27.0 bundle --composed)
- Default (inline) bundling does not panic; only
--composed / BundleBytesComposed does.
Minimal reproduction
tags65.yaml (65 entries — odd):
tags:
- name: Tag0
description: d0
# ... 65 entries total
spec65.yaml:
openapi: 3.0.2
info: {title: t, version: 1.0.0}
tags:
$ref: tags65.yaml#/tags
paths:
/x:
get:
responses:
"200": {description: ok}
vacuum bundle --composed spec65.yaml out.json
It depends purely on array-length parity
tags length |
bundle --composed |
| 64 (even) |
✅ success, bundle written |
| 65 (odd) |
❌ panic: index out of range [65] with length 65 |
| 63 (odd) |
❌ panic: index out of range [63] with length 63 |
Generate the tags file with, e.g.:
node -e "let s='tags:\n'; for(let i=0; i<65; i++)s+='- name: Tag'+i+'\n description: d'+i+'\n'; require('fs').writeFileSync('tags65.yaml',s)"
Panic / stack trace
panic: runtime error: index out of range [65] with length 65
goroutine 1 [running]:
github.com/pb33f/libopenapi/bundler.walkAndRewriteRefs(...)
.../libopenapi@v0.37.2/bundler/composer_functions.go:735 +0x1e0
github.com/pb33f/libopenapi/bundler.walkAndRewriteRefs(...)
.../libopenapi@v0.37.2/bundler/composer_functions.go:746 +0x1c4
github.com/pb33f/libopenapi/bundler.walkAndRewriteRefs(...)
.../libopenapi@v0.37.2/bundler/composer_functions.go:719 +0x84
github.com/pb33f/libopenapi/bundler.rewriteAllRefs(...)
.../libopenapi@v0.37.2/bundler/composer_functions.go:702
github.com/pb33f/libopenapi/bundler.compose(...)
.../libopenapi@v0.37.2/bundler/bundler.go:686 +0x540
github.com/pb33f/libopenapi/bundler.BundleBytesComposed(...)
.../libopenapi@v0.37.2/bundler/bundler.go:371 +0xa8
Likely root cause
walkAndRewriteRefs appears to iterate node content as key/value mapping pairs:
for i := 0; i < len(node.Content); i += 2 {
valueNode := node.Content[i+1] // assumes even length
}
When the walker reaches the resolved tags node — a sequence of N items rather than a mapping — it still steps by 2 and reads Content[i+1], which only stays in bounds when N is even. With odd N, at i = N-1 it reads Content[N] on a slice of length N → out of range. The [N] with length N message and the exact even/odd parity behavior above point at a missing node-kind guard (SequenceNode vs MappingNode) and/or bounds check before Content[i+1].
Expected
Composed bundling should handle a $ref that resolves to an array node (such as root-level tags) regardless of its length, the same way inline bundling and other tools (e.g. Redocly) do.
Summary
BundleBytesComposed(composed bundling) panics withruntime error: index out of range [N] with length Nwhen the document contains a$refthat resolves to an array (sequence) node with an odd number of elements. A top-leveltags: {$ref: tags.yaml#/tags}pointing at an odd-length tag list reproduces it reliably.vacuumv0.27.0bundle --composed)--composed/BundleBytesComposeddoes.Minimal reproduction
tags65.yaml(65 entries — odd):spec65.yaml:It depends purely on array-length parity
tagslengthbundle --composedindex out of range [65] with length 65index out of range [63] with length 63Generate the tags file with, e.g.:
Panic / stack trace
Likely root cause
walkAndRewriteRefsappears to iterate node content as key/value mapping pairs:When the walker reaches the resolved
tagsnode — a sequence of N items rather than a mapping — it still steps by 2 and readsContent[i+1], which only stays in bounds when N is even. With odd N, ati = N-1it readsContent[N]on a slice of length N → out of range. The[N] with length Nmessage and the exact even/odd parity behavior above point at a missing node-kind guard (SequenceNode vs MappingNode) and/or bounds check beforeContent[i+1].Expected
Composed bundling should handle a
$refthat resolves to an array node (such as root-leveltags) regardless of its length, the same way inline bundling and other tools (e.g. Redocly) do.