pydantic/monty · error · TypeError
Must have exactly one of create/read/write/append mode and a
Error message
Must have exactly one of create/read/write/append mode and at most one plus
What it means
`canonicalFileMode` parses the Python-style open mode and requires exactly one primary action character (r/w/a) plus at most one '+'; an empty mode string fails immediately. This mirrors CPython's `open()` mode validation for the subset Monty supports.
Source
Thrown at crates/monty-js/ts/types.ts:122
}
/** Whether the mode permits writes. */
get writable(): boolean {
return this.mode.startsWith('w') || this.mode.startsWith('a') || this.mode.includes('+')
}
/** Treats handles decoded by the native transport as instances too. */
static [Symbol.hasInstance](value: unknown): boolean {
return (
typeof value === 'object' && value !== null && (value as Record<string, unknown>).__monty_type__ === 'FileHandle'
)
}
}
/** Canonicalizes the subset of Python file modes Monty supports. */
export function canonicalFileMode(mode: string): string {
if (mode.length === 0) {
throw new TypeError('Must have exactly one of create/read/write/append mode and at most one plus')
}
let action: string | undefined
let binary = false
let text = false
for (const char of mode) {
if (char === 'r' || char === 'w' || char === 'a') {
if (action !== undefined) throw new TypeError('must have exactly one of create/read/write/append mode')
action = char
} else if (char === 'x') {
throw new TypeError('exclusive creation mode is not supported')
} else if (char === 'b') {
if (binary) throw new TypeError('invalid mode: binary mode specified twice')
binary = true
} else if (char === 't') {
if (text) throw new TypeError('invalid mode: text mode specified twice')
text = true
} else if (char === '+') {View on GitHub (pinned to adc986b362)
Solutions
- Pass a non-empty mode string: 'r', 'w', 'a', optionally with '+' (e.g. 'r+', 'w+').
- Check the mode-mapping logic that produced the empty string and default to 'r' when no action is requested.
- Validate the mode before constructing the handle.
Example fix
// before const mode = flags.includePlus ? '+' : ''; // empty when no plus // after const mode = flags.includePlus ? 'r+' : 'r';
Defensive patterns
Strategy: validation
Validate before calling
if (typeof mode !== 'string' || mode.length === 0) throw new TypeError('mode required, e.g. r/w/a plus optional +'); Try / catch
try {
return new MontyFileHandle(path, mode);
} catch (e) {
if (e instanceof TypeError && e.message.startsWith('Must have exactly one of')) {
return new MontyFileHandle(path, 'r');
}
throw e;
} Prevention
- Never build mode strings by concatenation that can yield ''
- Default the base action to 'r' when the sandbox does not specify one
- Enumerate supported modes ('r','w','a','r+','w+','a+','rb','wb','ab') explicitly
When it happens
Trigger: Calling `new MontyFileHandle(path, '')` or returning a file handle from an `open` OS callback with an empty-string mode.
Common situations: The host builds the mode dynamically (e.g. concatenating flags) and ends up with an empty string when no flag matched; or the sandbox requested a mode that the callback maps to nothing.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- must have exactly one of create/read/write/append mode
- Max input depth exceeded
- ClassInstance marker instanceId must be a uuid string
- ${field} must be 'all', undefined or a list/Set of names, go
- memoryUsageLimit must be a non-negative safe integer
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/dac6ddf7dad6b9f6.
Report an issue: GitHub.