badges/shields · error · ValidationError

Field `${field}` must be of type string

Error message

Field `${field}` must be of type string

What it means

The fields labelColor, color, message, label, and logoBase64 must be strings when present. _validate iterates these fields (badge-maker/lib/index.js:18-23) and throws if a provided value has any other typeof. This prevents malformed SVG output from numbers, booleans, or objects reaching the renderer.

Source

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

 */

import _makeBadge from './make-badge.js'

export class ValidationError extends Error {}

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')
        }
      })
    }

View on GitHub (pinned to 766fd8bc89)

Solutions

  1. Coerce the value to a string: makeBadge({ message: String(buildNumber) })
  2. If the value is a boolean/status, map it to a string first: message: passed ? 'passing' : 'failing'
  3. Validate the descriptor shape before calling makeBadge

Example fix

// before
const svg = makeBadge({ label: 'build', message: buildNumber }) // 123
// after
const svg = makeBadge({ label: 'build', message: String(buildNumber) })
Defensive patterns

Strategy: type-guard

Validate before calling

for (const f of ['labelColor', 'color', 'message', 'label', 'logoBase64']) {
  if (f in badge && typeof badge[f] !== 'string') {
    throw new Error(`badge field ${f} must be a string`)
  }
}
const svg = makeBadge(badge)

Type guard

function isBadgeStringField(v) {
  return typeof v === 'string'
}
// usage: if (isBadgeStringField(badge.message)) makeBadge(badge)

Try / catch

try {
  return makeBadge(badge)
} catch (e) {
  if (e instanceof ValidationError && e.message.includes('must be of type string')) {
    const field = e.message.match(/Field `(.+)`/)[1]
    return makeBadge({ ...badge, [field]: String(badge[field]) })
  }
  throw e
}

Prevention

When it happens

Trigger: makeBadge({ message: 42 }), makeBadge({ label: { text: 'build' } }), makeBadge({ color: true }), or makeBadge({ message: ['passing'] }) — any non-string value assigned to one of the five string fields.

Common situations: Numbers from CI (build number 123 as message), boolean success flags passed directly as message, colors read from JSON where they were numeric, or template variables that hold non-string types from an API response.

Related errors


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