Skip to content

Composed bundler panics with "index out of range" when a $ref resolves to an odd-length array (e.g. root tags) #607

Description

@jorgembfigueira

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions