Skip to content

Circular merge aliases may cause RangeError despite maxAliasCount during JS conversion #677

@yuki-matsuhashi

Description

@yuki-matsuhashi

Describe the bug

Converting a YAML document with a cyclic merge alias to native JavaScript may throw a RangeError: Maximum call stack size exceeded, even when maxAliasCount is set.

This appears to affect aliases reached through YAML merge handling, where the usual maxAliasCount handling does not appear to stop recursive merge resolution before stack overflow.

To Reproduce

const { parse } = require('yaml')
parse('&A { <<: *A }', { maxAliasCount: 0, merge: true })

Output

RangeError: Maximum call stack size exceeded
    at Object.visit (/poc/node_modules/yaml/dist/visit.js:38:15)
    at Alias.resolve (/poc/node_modules/yaml/dist/nodes/Alias.js:30:19)
    at Scalar.addMergeToJSMap [as addToJSMap] (/poc/node_modules/yaml/dist/schema/yaml-1.1/merge.js:31:52)
    at Object.addPairToJSMap (/poc/node_modules/yaml/dist/nodes/addPairToJSMap.js:11:13)
    at YAMLMap.toJSON (/poc/node_modules/yaml/dist/nodes/YAMLMap.js:124:28)
    at mergeValue (/poc/node_modules/yaml/dist/schema/yaml-1.1/merge.js:45:27)
    at Scalar.addMergeToJSMap [as addToJSMap] (/poc/node_modules/yaml/dist/schema/yaml-1.1/merge.js:39:9)
    at Object.addPairToJSMap (/poc/node_modules/yaml/dist/nodes/addPairToJSMap.js:11:13)
    at YAMLMap.toJSON (/poc/node_modules/yaml/dist/nodes/YAMLMap.js:124:28)
    at mergeValue (/poc/node_modules/yaml/dist/schema/yaml-1.1/merge.js:45:27)

Expected behaviour

I would expect cyclic merge aliases to either be stopped by maxAliasCount, or to fail with a controlled error rather than recursing until stack overflow.

Versions (please complete the following information):

  • Node.js v24.15.0
  • yaml: reproduced with 2.8.3, 2.0.0, 1.10.3, and 1.5.0

Additional context

This seems related to the existing circular-reference behavior for merge handling. The difference here is that recursive merge resolution is still reached while maxAliasCount is set.

yaml/tests/doc/anchors.ts

Lines 458 to 465 in 93c951b

test('circular reference', () => {
const src = '&A { <<: *A, B: b }\n'
const doc = parseDocument(src, { merge: true })
expect(doc.errors).toHaveLength(0)
expect(doc.warnings).toHaveLength(0)
expect(() => doc.toJS()).toThrow('Maximum call stack size exceeded')
expect(String(doc)).toBe(src)
})

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions