badges/shields · error · ValidationError
Unexpected field '${key}'. Allowed values are (${expectedKey
Error message
Unexpected field '${key}'. Allowed values are (${expectedKeys.toString()}) What it means
makeBadge only accepts a fixed set of keys: label, message, labelColor, color, style, logoBase64, links, idSuffix. In _clean (badge-maker/lib/index.js:74-84), any key that is not in this whitelist throws — including null-valued unknown keys — because a null/unknown key falls into the else branch. This catches typos and stale options early.
Source
Thrown at badge-maker/lib/index.js:80
const expectedKeys = [
'label',
'message',
'labelColor',
'color',
'style',
'logoBase64',
'links',
'idSuffix',
]
const cleaned = {}
Object.keys(format).forEach(key => {
if (format[key] != null && key === 'logoBase64') {
cleaned.logo = format[key]
} else if (format[key] != null && expectedKeys.includes(key)) {
cleaned[key] = format[key]
} else {
throw new ValidationError(
`Unexpected field '${key}'. Allowed values are (${expectedKeys.toString()})`,
)
}
})
// Legacy.
cleaned.label = cleaned.label || ''
return cleaned
}
/**
* Create a badge
*
* @param {object} format Object specifying badge data
* @param {string} format.label (Optional) Badge label (e.g: 'build')
* @param {string} format.message (Required) Badge message (e.g: 'passing')
* @param {string} format.labelColor (Optional) Label colorView on GitHub (pinned to 766fd8bc89)
Solutions
- Remove unknown keys or fix the typo so the key matches the whitelist exactly
- For optional fields, omit the key rather than setting it to null — note null values for KNOWN keys also throw here
- Filter the descriptor: Object.fromEntries(Object.entries(o).filter(([k, v]) => v != null))
Example fix
// before
const svg = makeBadge({ label: 'build', message: 'passing', colour: 'green' })
// after
const svg = makeBadge({ label: 'build', message: 'passing', color: 'green' }) Defensive patterns
Strategy: type-guard
Validate before calling
const ALLOWED = ['label', 'message', 'labelColor', 'color', 'style', 'logoBase64', 'links', 'idSuffix']
for (const key of Object.keys(badge)) {
if (!ALLOWED.includes(key) || badge[key] == null) {
throw new Error(`bad descriptor key/value: ${key}`)
}
}
const svg = makeBadge(badge) Type guard
function isCleanDescriptor(v) {
const allowed = ['label','message','labelColor','color','style','logoBase64','links','idSuffix']
return typeof v === 'object' && v !== null &&
Object.keys(v).every(k => allowed.includes(k) && v[k] != null)
} Try / catch
try {
return makeBadge(badge)
} catch (e) {
if (e instanceof ValidationError && e.message.startsWith('Unexpected field')) {
const key = e.message.match(/'(.+)'/)[1]
const { [key]: _, ...rest } = badge
return makeBadge(rest)
}
throw e
} Prevention
- Check option spelling against the whitelist (color not colour, logoBase64 not logo)
- Do not spread arbitrary config objects into the descriptor
- Omit optional keys instead of setting them to null — null known keys also throw in _clean
- Type the descriptor in TypeScript as the library's BadgeOptions interface
When it happens
Trigger: makeBadge({ message: 'x', colours: 'green' }) (typo), makeBadge({ message: 'x', labelColor: null, color: null }) (explicit nulls hit the else branch since format[key] != null fails), or passing extra metadata keys (e.g. { message: 'x', id: 1 }).
Common situations: Misspelling an option name ('colour' vs 'color', 'logo' vs 'logoBase64'), spreading an unrelated config object into the descriptor, carrying over option names from other badge libraries, or explicitly setting a field to null expecting it to be ignored.
Related errors
- Field `${field}` must be of type string
- makeBadge takes an argument of type object
- Field `message` is required
- Field `links` must be an array of strings
- Field `links` must not have more than 2 elements
AI-assisted analysis of badges/shields@766fd8bc89 (2026-08-30).
Data as JSON: /api/errors/47bb855a990490ba.
Report an issue: GitHub.