badges/shields · error · ValidationError

Field `links` must be an array of strings

Error message

Field `links` must be an array of strings

What it means

When the optional `links` field is provided it must be an array. _validate checks Array.isArray(format.links) (badge-maker/lib/index.js:26) and throws this ValidationError if links is a string, object, or any non-array value. This is the not-an-array branch of the links validation.

Source

Thrown at badge-maker/lib/index.js:27

function _validate(format) {
  if (format !== Object(format)) {
    throw new ValidationError('makeBadge takes an argument of type object')
  }

  if (!('message' in format)) {
    throw new ValidationError('Field `message` is required')
  }

  const stringFields = ['labelColor', 'color', 'message', 'label', 'logoBase64']
  stringFields.forEach(function (field) {
    if (field in format && typeof format[field] !== 'string') {
      throw new ValidationError(`Field \`${field}\` must be of type string`)
    }
  })

  if ('links' in format) {
    if (!Array.isArray(format.links)) {
      throw new ValidationError('Field `links` must be an array of strings')
    } else {
      if (format.links.length > 2) {
        throw new ValidationError(
          'Field `links` must not have more than 2 elements',
        )
      }
      format.links.forEach(function (field) {
        if (typeof field !== 'string') {
          throw new ValidationError('Field `links` must be an array of strings')
        }
      })
    }
  }

  const styleValues = [
    'plastic',
    'flat',
    'flat-square',

View on GitHub (pinned to 766fd8bc89)

Solutions

  1. Wrap the link in an array: links: ['https://example.com']
  2. Normalize before calling: links: Array.isArray(link) ? link : [link]
  3. Omit the links field entirely if you have no links (undefined/null keys are dropped by _clean)

Example fix

// before
const svg = makeBadge({ message: 'docs', links: 'https://example.com' })
// after
const svg = makeBadge({ message: 'docs', links: ['https://example.com'] })
Defensive patterns

Strategy: type-guard

Validate before calling

if ('links' in badge && !Array.isArray(badge.links)) {
  badge.links = [badge.links]
}
const svg = makeBadge(badge)

Type guard

function isStringArray(v) {
  return Array.isArray(v) && v.every(x => typeof x === 'string')
}

Try / catch

try {
  return makeBadge(badge)
} catch (e) {
  if (e instanceof ValidationError && e.message.includes('`links`')) {
    return makeBadge({ ...badge, links: [].concat(badge.links).filter(l => typeof l === 'string') })
  }
  throw e
}

Prevention

When it happens

Trigger: makeBadge({ message: 'docs', links: 'https://example.com' }) — a single URL string instead of an array; also links: {} or links: 5. Any truthy links value that fails Array.isArray.

Common situations: Passing one link as a bare string because a single link 'obviously' doesn't need an array; deserializing config from YAML/TOML where a single-element link becomes a scalar; a template variable that is sometimes a string and sometimes an array.

Related errors


AI-assisted analysis of badges/shields@766fd8bc89 (2026-08-30). Data as JSON: /api/errors/29d438c331b5e352. Report an issue: GitHub.