serverless/serverless · error · ServerlessError

LEGACY_CONFIGURATION_PROPERTY_MERGE_INVALID_INPUT

LEGACY_CONFIGURATION_PROPERTY_MERGE_INVALID_INPUT

Error message

Non-object value specified in ${key} array: ${value}

What it means

`mergeArrays` supports a legacy form where `resources` or `functions` is an array of objects to deep-merge with lodash `_.merge`. If any element of that array is truthy but not an object (a string, number, etc.), the merge cannot proceed and this error throws. Falsy elements are silently skipped.

Source

Thrown at packages/serverless/lib/classes/service.js:246

        this.functions[functionName].events = []
      }

      if (!functionObj.name) {
        this.functions[functionName].name =
          `${this.service}-${stageNameForFunction}-${functionName}`
      }
    })
  }

  mergeArrays() {
    ;['resources', 'functions'].forEach((key) => {
      if (Array.isArray(this[key])) {
        this[key] = this[key].reduce((memo, value) => {
          if (value) {
            if (typeof value === 'object') {
              return _.merge(memo, value)
            }
            throw new ServerlessError(
              `Non-object value specified in ${key} array: ${value}`,
              'LEGACY_CONFIGURATION_PROPERTY_MERGE_INVALID_INPUT',
            )
          }

          return memo
        }, {})
      }
    })
  }

  async validate() {
    const userConfig = this.initialServerlessConfig

    // Ensure to validate normalized (after mergeArrays) input
    if (userConfig.functions) userConfig.functions = this.functions
    if (userConfig.resources) userConfig.resources = this.resources

View on GitHub (pinned to b9d7ea51c8)

Solutions

  1. Ensure every element of the `resources`/`functions` array is an object.
  2. Move descriptive strings into a `Description:` CloudFormation property inside an object, not as a bare array item.
  3. Use `serverless print` to dump the array and find the offending scalar element.

Example fix

# before
resources:
  - 'my stack'
  - Resources:
      MyBucket:
        Type: AWS::S3::Bucket
# after
resources:
  - Description: 'my stack'
  - Resources:
      MyBucket:
        Type: AWS::S3::Bucket
Defensive patterns

Strategy: validation

Validate before calling

for (const key of ['resources', 'functions']) {
  if (Array.isArray(config[key])) {
    config[key].forEach((el, i) => {
      if (el && typeof el !== 'object') {
        throw new Error(`${key}[${i}] must be an object, got ${typeof el}`)
      }
    })
  }
}

Type guard

const isValidArrayForm = (v) => !Array.isArray(v) || v.every((el) => el == null || typeof el === 'object')

Try / catch

try {
  service.mergeArrays()
} catch (e) {
  if (e.code === 'LEGACY_CONFIGURATION_PROPERTY_MERGE_INVALID_INPUT') { console.error('Remove non-object entries from resources/functions arrays'); process.exit(1) }
  throw e
}

Prevention

When it happens

Trigger: `resources: [...]` or `functions: [...]` where at least one element is a non-null primitive, e.g. `resources: ['description', { Resources: {...} }]`.

Common situations: Composing multiple CloudFormation snippet files where one file accidentally exports a string comment; YAML lists that mixed a scalar header with object fragments; hand-merged configs from pull requests that pasted a string into the resources array.

Related errors


AI-assisted analysis of serverless/serverless@b9d7ea51c8 (2026-08-13). Data as JSON: /api/errors/4c48a89f0711d395. Report an issue: GitHub.