{"record":{"id":"803b3488daf3710e","repo":"pydantic/monty","slug":"must-have-exactly-one-of-create-read-write-append-mode","errorCode":null,"errorMessage":"must have exactly one of create/read/write/append mode","messagePattern":"must have exactly one of create/read/write/append mode","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"crates/monty-js/ts/types.ts","lineNumber":130,"sourceCode":"  static [Symbol.hasInstance](value: unknown): boolean {\n    return (\n      typeof value === 'object' && value !== null && (value as Record<string, unknown>).__monty_type__ === 'FileHandle'\n    )\n  }\n}\n\n/** Canonicalizes the subset of Python file modes Monty supports. */\nexport function canonicalFileMode(mode: string): string {\n  if (mode.length === 0) {\n    throw new TypeError('Must have exactly one of create/read/write/append mode and at most one plus')\n  }\n\n  let action: string | undefined\n  let binary = false\n  let text = false\n  for (const char of mode) {\n    if (char === 'r' || char === 'w' || char === 'a') {\n      if (action !== undefined) throw new TypeError('must have exactly one of create/read/write/append mode')\n      action = char\n    } else if (char === 'x') {\n      throw new TypeError('exclusive creation mode is not supported')\n    } else if (char === 'b') {\n      if (binary) throw new TypeError('invalid mode: binary mode specified twice')\n      binary = true\n    } else if (char === 't') {\n      if (text) throw new TypeError('invalid mode: text mode specified twice')\n      text = true\n    } else if (char === '+') {\n      throw new TypeError(\"update modes ('+') are not yet supported\")\n    } else {\n      throw new TypeError(`invalid mode: '${char}'`)\n    }\n  }\n  if (binary && text) throw new TypeError(\"can't have text and binary mode at once\")\n  if (action === undefined) {\n    throw new TypeError('Must have exactly one of create/read/write/append mode and at most one plus')","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty-js/ts/types.ts#L112-L148","documentation":"`canonicalFileMode` requires exactly one primary action character ('r', 'w', or 'a'); encountering a second one raises this TypeError. This matches CPython's message for invalid combinations of open-mode action characters.","triggerScenarios":"Calling `new MontyFileHandle(path, 'rw')`, `'ra'`, `'wr'`, etc. — a mode containing two action characters. Note 'x' (exclusive creation) raises a different error.","commonSituations":"Devs familiar with C's fopen accept strings like 'rw+' assume Python accepts them; or mode strings are built by concatenating per-feature flags without ensuring only one action.","solutions":["Use exactly one action character: 'r', 'w', or 'a', plus at most one '+' (e.g. 'r+', 'w+', 'a+').","Fix flag-concatenation code so it picks a single base action instead of appending multiple.","If read+write is intended, use 'r+' (or 'w+' to truncate)."],"exampleFix":"// before\nnew MontyFileHandle(path, 'rw');\n\n// after\nnew MontyFileHandle(path, 'r+');","handlingStrategy":"validation","validationCode":"const actions = [...mode].filter(c => 'rwa'.includes(c)).length;\nif (actions !== 1) throw new TypeError(`mode must contain exactly one of r/w/a, got '${mode}'`);","typeGuard":null,"tryCatchPattern":"try {\n  return new MontyFileHandle(path, mode);\n} catch (e) {\n  if (e instanceof TypeError && e.message === 'must have exactly one of create/read/write/append mode') {\n    throw new TypeError(`unsupported mode '${mode}'; use r/w/a with optional +`);\n  }\n  throw e;\n}","preventionTips":["Remember Python open modes are not C fopen modes: 'rw' is invalid, use 'r+'","Build modes from one base action plus flags, never by appending multiple actions","Map user-supplied intents (read/write/append) to a fixed mode table"],"tags":["file-mode","validation","file-handle","python-compat"],"backgroundTag":"invalid-argument-value","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}