{"record":{"id":"7df0c8991b5cde9a","repo":"pydantic/monty","slug":"montyfilehandle-path-must-be-a-string","errorCode":null,"errorMessage":"MontyFileHandle path must be a string","messagePattern":"MontyFileHandle path must be a string","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"crates/monty-js/ts/types.ts","lineNumber":84,"sourceCode":"}\n\n/**\n * Host-side handle to a file opened inside a Monty sandbox.\n *\n * This is a plain data holder, never a live host file descriptor. Return one\n * from an `open` OS callback so Monty can construct its sandboxed file object.\n */\nexport class MontyFileHandle {\n  /** Virtual POSIX sandbox path, never a host path. */\n  readonly path: string\n  /** Canonical Python `open()` mode, such as `'r'`, `'rb'`, or `'w'`. */\n  readonly mode: string\n  /** Current character or byte position. */\n  readonly position: number\n\n  /** Constructs a file handle to return from an `open` OS callback. */\n  constructor(path: string, mode: string, options: MontyFileHandleOptions = {}) {\n    if (typeof path !== 'string') throw new TypeError('MontyFileHandle path must be a string')\n    if (typeof mode !== 'string') throw new TypeError('MontyFileHandle mode must be a string')\n    const position = options.position ?? 0\n    validateFilePosition(position)\n\n    this.path = path\n    this.mode = canonicalFileMode(mode)\n    this.position = position\n    Object.defineProperty(this, '__monty_type__', { value: 'FileHandle' })\n    Object.freeze(this)\n  }\n\n  /** Whether the mode opens the file in binary form. */\n  get binary(): boolean {\n    return this.mode.includes('b')\n  }\n\n  /** Whether the mode permits reads. */\n  get readable(): boolean {","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty-js/ts/types.ts#L66-L102","documentation":"The `MontyFileHandle` constructor validates that the `path` argument is a JavaScript string, since the handle is returned from an `open` OS callback and the wire protocol requires a textual virtual path. Passing a non-string (number, Path object, undefined, etc.) is rejected up front with a TypeError.","triggerScenarios":"Constructing `new MontyFileHandle(path, mode)` inside an `open` OS callback where `path` came from loosely typed input — e.g. destructured callback args, a `Path`-like object, a number, or `undefined` from a missing argument.","commonSituations":"Host callback code receives the open request as an untyped/`any` value (or from JS after a refactor) and forwards it directly; TypeScript compilation is skipped or the value was cast.","solutions":["Coerce/validate the path to a string before constructing: `new MontyFileHandle(String(path), mode)` only if a string is truly intended.","Check where the value comes from — the OS callback should pass its `path` field, not the whole request object.","Add `typeof path === 'string'` validation at the callback boundary."],"exampleFix":"// before\nconst handle = new MontyFileHandle(request, mode); // request object, not string\n\n// after\nconst handle = new MontyFileHandle(request.path, mode);","handlingStrategy":"validation","validationCode":"function assertString(v, name) { if (typeof v !== 'string') throw new TypeError(`${name} must be a string`); return v; }\nassertString(path, 'path');","typeGuard":"const isPath = (v: unknown): v is string => typeof v === 'string' && v.length > 0;","tryCatchPattern":"try {\n  return new MontyFileHandle(path, mode);\n} catch (e) {\n  if (e instanceof TypeError && /must be a string/.test(e.message)) {\n    throw new TypeError(`open callback got invalid path: ${typeof path}`);\n  }\n  throw e;\n}","preventionTips":["In open OS callbacks always use the typed `path` field, not the whole request object","Keep TypeScript strict mode on so non-string values cannot reach the constructor","Avoid blind String() coercion of structured values"],"tags":["typescript","type-check","file-handle","constructor"],"backgroundTag":"type-mismatch","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"}