Skip to content

Arazzo.Render panics with a nil pointer dereference when an extension has an empty value #693

Open

Description

@JayOfTheKeyboard

Summary

(*high.Arazzo).Render() panics with a nil pointer dereference when any extension in the document has an empty value, such as x-a: with nothing after it. NewArazzoDocument accepts the document without an error, and the panic happens on render. It happens at the root, in info and in a workflow. The panic isn't recovered, so it takes down the calling program.

The same x-a: line in an OpenAPI 3.1 document builds and renders fine.

Reproduction

package main

import (
	"fmt"

	"github.com/pb33f/libopenapi"
)

func main() {
	doc, err := libopenapi.NewArazzoDocument([]byte("arazzo: 1.0.1\ninfo:\n  title: t\n  version: '1'\nx-a:\n"))
	fmt.Println("build error:", err)
	out, err := doc.Render()
	fmt.Println(string(out), err)
}

Actual

panic: runtime error: invalid memory address or nil pointer dereference

Moving x-a: into info or into a workflow (workflows: [{workflowId: w, x-a: }]) gives the same panic.

Expected

The document renders with x-a: kept as an empty value, the way the OpenAPI path renders it.

Likely cause

orderedmap.(*Map).MarshalYAML (orderedmap/builder.go:59) calls valueNode.Encode(value) on the extension's node, which is a !!null scalar with an empty value. go-yaml's Node.Encode then dereferences doc.Content[0] on an empty document (internal/libyaml/node.go:348 in pb33f/go-yaml v0.1.1). That part is go-yaml/yaml#1014. #301 hit the same thing on the OpenAPI side, and #302 fixed it in datamodel/high/node_builder.go by using utils.CreateEmptyScalarNode() instead of encoding an empty null node. The Arazzo render goes through orderedmap instead and doesn't have that check.

Fix

I have a fix ready that adds the same check to orderedmap.(*Map).MarshalYAML: an empty !!null scalar node becomes utils.CreateEmptyScalarNode() instead of being encoded. A new TestNewArazzoDocument_RenderEmptyExtension covers the root, info and workflow cases. All three panic without the change and pass with it, and the rendered output keeps x-a: the same way the OpenAPI render does. go test ./... and go test -race ./... pass with it on Go 1.26.0, the version in go.mod. Happy to open a PR.

Environment

  • libopenapi main at 07d595c
  • Go 1.27.3, linux/amd64

(Found by fuzzing and reproduced with the help of an AI coding assistant.)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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