badges/shields · error · ValidationError

Field `idSuffix` must contain only numbers, letters, -, and

Error message

Field `idSuffix` must contain only numbers, letters, -, and _

What it means

The optional `idSuffix` field (used to disambiguate SVG element IDs when several badges appear on the same page) must match /^[a-zA-Z0-9\-_]*$/ — only letters, numbers, hyphens, and underscores. _validate enforces this (badge-maker/lib/index.js:54) because the value is embedded in generated SVG IDs/markup and must be safe.

Source

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

        }
      })
    }
  }

  const styleValues = [
    'plastic',
    'flat',
    'flat-square',
    'for-the-badge',
    'social',
  ]
  if ('style' in format && !styleValues.includes(format.style)) {
    throw new ValidationError(
      `Field \`style\` must be one of (${styleValues.toString()})`,
    )
  }
  if ('idSuffix' in format && !/^[a-zA-Z0-9\-_]*$/.test(format.idSuffix)) {
    throw new ValidationError(
      'Field `idSuffix` must contain only numbers, letters, -, and _',
    )
  }
}

function _clean(format) {
  const expectedKeys = [
    'label',
    'message',
    'labelColor',
    'color',
    'style',
    'logoBase64',
    'links',
    'idSuffix',
  ]

  const cleaned = {}

View on GitHub (pinned to 766fd8bc89)

Solutions

  1. Sanitize the suffix: idSuffix: raw.replace(/[^a-zA-Z0-9\-_]/g, '-')
  2. Use simple counters or slugs: idSuffix: String(index) or slugified names
  3. Omit idSuffix entirely if you render only one badge per page

Example fix

// before
const svg = makeBadge({ message: 'v1.0', idSuffix: `badge ${name}` })
// after
const svg = makeBadge({ message: 'v1.0', idSuffix: `badge-${name}`.replace(/[^a-zA-Z0-9\-_]/g, '-') })
Defensive patterns

Strategy: validation

Validate before calling

if ('idSuffix' in badge && !/^[a-zA-Z0-9\-_]*$/.test(badge.idSuffix)) {
  badge.idSuffix = badge.idSuffix.replace(/[^a-zA-Z0-9\-_]/g, '-')
}
const svg = makeBadge(badge)

Type guard

function isValidIdSuffix(v) {
  return typeof v === 'string' && /^[a-zA-Z0-9\-_]*$/.test(v)
}

Try / catch

try {
  return makeBadge(badge)
} catch (e) {
  if (e instanceof ValidationError && e.message.includes('idSuffix')) {
    return makeBadge({ ...badge, idSuffix: badge.idSuffix.replace(/[^a-zA-Z0-9\-_]/g, '-') })
  }
  throw e
}

Prevention

When it happens

Trigger: makeBadge({ message: 'x', idSuffix: 'badge #1' }), idSuffix: 'a.b', idSuffix: 'id/2', or any value containing spaces, dots, slashes, or other special characters.

Common situations: Using numeric counters with formatting (e.g. '1.0'), passing filenames or URLs as the suffix, or generating ids from untrusted/user input containing arbitrary characters.

Related errors


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