pydantic/monty · error · TypeError

${field} must be 'all', undefined or a list/Set of names, go

Error message

${field} must be 'all', undefined or a list/Set of names, got '${policy}'

What it means

Attribute exposure policies (e.g. attrs/read or write policy options) accept 'all', undefined, or a list/Set of attribute names. A bare string other than 'all' is rejected because it would otherwise be silently treated as a character array ('greet' -> 'g','r','e','e','t'). validatePolicy throws this TypeError naming the field and offending value.

Source

Thrown at crates/monty-js/ts/classInstance.ts:755

}

/** Canonical 8-4-4-4-12 hex uuid; case-insensitive since `normalizeId` lowercases. */
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i

/** Validates a caller-supplied wrapper id and lowercases it, so the id the
 *  sandbox reports back (always lowercase) is the key the store holds. */
function normalizeId(wrapperKind: string, id: string): string {
  if (typeof id !== 'string' || !UUID_PATTERN.test(id)) {
    throw new TypeError(`${wrapperKind} id must be a canonical uuid string, got ${JSON.stringify(id)}`)
  }
  return id.toLowerCase()
}

/** Rejects a string policy other than `'all'`: a bare `'greet'` would
 *  otherwise be treated as a character array (`'g'`, `'r'`, ...). */
function validatePolicy(field: string, policy: AttrPolicy | undefined): void {
  if (typeof policy === 'string' && policy !== 'all') {
    throw new TypeError(`${field} must be 'all', undefined or a list/Set of names, got '${policy}'`)
  }
}

/** Names no policy may expose, `'all'` or explicit: JS object machinery
 *  that would hand the sandbox the class, its prototype, or a call stack. */
const DENIED_NAMES: ReadonlySet<string> = new Set(['constructor', '__proto__', 'prototype', 'arguments', 'caller'])

/** Whether `policy` exposes `name`; `'all'` never exposes underscore names,
 *  and [`DENIED_NAMES`] are refused whichever form the policy takes. */
function policyAllows(policy: AttrPolicy | undefined, name: string): boolean {
  if (policy === undefined || DENIED_NAMES.has(name)) {
    return false
  }
  if (policy === 'all') {
    return !name.startsWith('_')
  }
  // Duck-type on `.has` rather than `instanceof Set` so set-likes from
  // another realm (iframe / VM context) work too.

View on GitHub (pinned to adc986b362)

Solutions

  1. Wrap names in an array: { attrs: ['greet'] }
  2. Use the literal 'all' if every attribute should be exposed
  3. If the value comes from config, coerce it: typeof p === 'string' && p !== 'all' ? p.split(',') : p

Example fix

// before
ClassType(MyClass, { attrs: 'greet' });
// after
ClassType(MyClass, { attrs: ['greet'] });
Defensive patterns

Strategy: validation

Validate before calling

function assertPolicy(p) {
  if (p !== undefined && p !== 'all' && !(Array.isArray(p) || p instanceof Set)) {
    throw new Error(`policy must be 'all', undefined or a list/Set, got ${JSON.stringify(p)}`);
  }
}
assertPolicy(opts.attrs);

Type guard

function isValidPolicy(p) {
  return p === undefined || p === 'all' || Array.isArray(p) || p instanceof Set;
}

Try / catch

try {
  const type = ClassType(MyClass, { attrs: policy });
} catch (e) {
  if (e instanceof TypeError && e.message.includes("must be 'all', undefined or a list/Set")) {
    throw new Error("use 'all' or an array of names, e.g. ['greet']");
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing options like { attrs: 'greet' } or { attrsWrite: 'name,age' } when registering a class, instead of 'all', undefined, ['greet'], or new Set(['greet']).

Common situations: Comma-separated string lists copied from config files; a single method name passed as a string assuming string-or-array support; dynamically built policies that degrade to strings.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13). Data as JSON: /api/errors/1a17109ef3061141. Report an issue: GitHub.