Skip to content

[overlay] incorrectly concatenates enum arrays during deep merge #792

Open

Description

@garciasdos

Description

When using bump overlay to apply an overlay that adds new properties to a schema, enum arrays from nested properties are incorrectly appended to existing enum arrays at different paths, resulting in duplicate values.

Environment

  • bump-cli version: 2.9.8
  • Node.js version: 24.x

Steps to Reproduce

  1. Have an OpenAPI spec with a property containing an enum:
# base-spec.yaml
paths:
  /items/{id}:
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                method:
                  type: string
                  enum: [GET, POST, PUT, DELETE]
  1. Apply an overlay that adds a nested object with a property of the same name:
# overlay.yaml
overlay: 1.0.0
actions:
  - target: $.paths['/items/{id}'].put.requestBody.content['application/json'].schema.properties
    update:
      request:
        type: object
        properties:
          method:
            type: string
            enum: [GET, POST, PUT, DELETE]
  1. Run: bump overlay base-spec.yaml overlay.yaml

Expected Behavior

The top-level method.enum should remain unchanged with 4 values:

method:
  enum: [GET, POST, PUT, DELETE]

And a new request.properties.method.enum should be added with 4 values.

Actual Behavior

The top-level method.enum is incorrectly modified to have 8 values (duplicated):

method:
  enum: [GET, POST, PUT, DELETE, GET, POST, PUT, DELETE]

Root Cause

In src/core/overlay.ts, the update method uses mergician with appendArrays: true:

const merger = mergician({ appendArrays: true });

This causes arrays to be concatenated during deep merge. When the overlay adds a nested property with the same name (method) containing an enum array, mergician appears to find and concatenate enum arrays from different schema paths.

Suggested Fix

#791

Activity

  1. fbraure commented on Feb 5, 2026

    @fbraure
    Contributor

    Thank you very much for pointing this out, creating an Issue and proposing a fix.

  2. paulRbr commented on Feb 10, 2026

    @paulRbr
    Member

    Hi @garciasdos, thanks for your contribution.

    I've tried the example definitions of your issue description in both a test case and manually by running the current CLI code (I also tested with version 2.9.8) and could not reproduce. You can see the test files in this commit.

    And the output:

    Image

    I'm not sure to understand where the issue lies. Could you elaborate please?

  3. garciasdos commented on Feb 23, 2026

    @garciasdos
    ContributorAuthor

    Hi @paulRbr, thanks for testing! Here's a simpler, directly reproducible example:

      # base-spec.yaml:
      openapi: 3.1.0
      info:
        title: Test API
        version: 1.0.0
      paths:
        /pets/{petId}:
          put:
            summary: Update a pet
            operationId: updatePet
            parameters:
              - name: petId
                in: path
                required: true
                schema:
                  type: string
            requestBody:
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      name:
                        type: string
                        description: The pet's name.
                      status:
                        type: string
                        description: The pet's status.
                        enum:
                          - available
                          - pending
                          - sold
            responses:
              '200':
                description: OK
      # overlay.yaml:
      overlay: 1.0.0
      info:
        title: Add fields to updatePet
        version: 1.0.0
      actions:
        - target: >-
            $.paths['/pets/{petId}']
              .put
              .requestBody
              .content['application/json']
              .schema
              .properties
          update:
            name:
              type: string
              description: Updated name of the pet.
            status:
              type: string
              description: Updated status of the pet.
              enum:
                - available
                - pending
                - sold
            tag:
              type: string
              description: A tag for the pet.

    Running bump overlay base-spec.yaml overlay.yaml produces duplicated enums:

      status:
        enum:
          - available
          - pending
          - sold
          - available
          - pending
          - sold

    The key is that the overlay targets .properties (an object)
    and updates a property (status) that already exists in the
    base spec with the same enum values. Since
    mergician({appendArrays: true}) deep-merges the overlay's
    status object into the base's status object, the enum arrays
    get concatenated instead of replaced.

    Tested with bump-cli 2.9.10.

  4. paulRbr commented on Feb 23, 2026

    @paulRbr
    Member

    Thanks @garciasdos for you answer. So basically you expect array merging to also apply uniqueness on the result.

    I have to admit this is not well specified in the Overlay specification, and maybe in most cases it does make sense. However I'm afraid that behavior is arbitrary depending on the use case.

    Imagine such a merge:

    Base document (and target object)

    groceries:
    - banana
    - tomato

    Overlay update

    update:
      groceries:
        - banana
        - onions

    Would one want to result with:

    grocieries:
    - banana
    - tomato
    - banana
    - onions

    or

    grocieries:
    - banana
    - tomato
    - onions

    It really depends if you expect to keep the count of each occurrence.

    Anyway, I'm ok with changing the default behavior to deduplicate array values as you suggest in #791. Let's see if other users have different usecases and we'll adapt then!

  5. garciasdos commented on Feb 23, 2026

    @garciasdos
    ContributorAuthor

    @paulRbr Thanks for applying the fix! Just a small clarification worth noting: deduplication here isn't just a matter of preferred default behavior — the OpenAPI/JSON Schema specification actually requires it.

    The JSON Schema spec explicitly states that enum must be "an array with at least one element, where each element is unique" (source). This means a spec with duplicate enum values is technically invalid, so any tool applying overlays that result in duplicated enum entries would produce a non-conformant document.

  6. paulRbr commented on Feb 24, 2026

    @paulRbr
    Member

    Thanks for pointing that out. Indeed for enum arrays in JSON schema that would be the case. However Overlay don't act only on those arrays. They can merge any type of arrays but I agree that it's safer to act with deduped arrays by default.

    Thanks again for your analysis and fix. We will release a new version of the CLI this week.

  7. paulRbr commented on Apr 11, 2026

    @paulRbr
    Member

    Here's a use case where array duplication is necessary #818

    So we need to find a better way to do so. (Probably apply the deduplication only on enum fields)

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