{"record":{"id":"0e54c4e4781bbf4b","repo":"jgraph/drawio-desktop","slug":"bad-arg-name","errorCode":null,"errorMessage":"bad arg: ${name}","messagePattern":"bad arg: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/electron.js","lineNumber":3177,"sourceCode":"\t\tif (c1 == '<' && c2 == 'm' && c3 == 'x')\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n};\n\nfunction isConflict(origStat, stat)\n{\n\treturn stat != null && origStat != null && stat.mtimeMs != origStat.mtimeMs;\n};\n\nfunction reqStr(v, name)\n{\n\tif (typeof v !== 'string' || !v)\n\t{\n\t\tthrow new Error('bad arg: ' + name);\n\t}\n\n\treturn v;\n}\n\n// Returns true if `realpath` is a draft- or backup-naming variant of any path\n// in blessedPaths (same directory, basename starts with DRAFT_PREFEX +\n// origBasename or BKP_PREFEX + origBasename). Drafts and backups are\n// derivative — drawio writes them as siblings of files the user opened.\nfunction isDraftOrBkpOfBlessed(realpath)\n{\n\tconst dir = path.dirname(realpath);\n\tconst base = path.basename(realpath);\n\n\tfor (const blessed of blessedPaths)\n\t{\n\t\tif (path.dirname(blessed) !== dir) continue;\n","sourceCodeStart":3159,"sourceCodeEnd":3195,"githubUrl":"https://github.com/jgraph/drawio-desktop/blob/403a2cb79f431db13a395f033b67eeebc1631754/src/main/electron.js#L3159-L3195","documentation":"reqStr(v, name) (src/main/electron.js:3173-3181) is the canonical string validator for renderer->main IPC arguments. It throws 'bad arg: <name>' whenever v is not a string or is the empty string. The rendererReq handler calls it on fileObject.path, path, filename, and file before any write-side action (lines 3842, 3846, 3851, 3856, 3861, 3889, 3893, 3900, 3904, 3908, 3918).","triggerScenarios":"An IPC request whose required string field is undefined, null, a number, an object, or '' — e.g. saveFile with fileObject.path missing, writeFile with args.path null, readFile with args.filename = ''.","commonSituations":"Renderer sends a stale fileObject after a 'new diagram' reset where path was cleared; a custom integration calling electron.request with the wrong field names; a payload truncated by structured-clone over the contextBridge (functions/Symbols dropped).","solutions":["Inspect the exact field named in the message (e.g. 'bad arg: fileObject.path') and ensure the renderer sets that field to a non-empty string before dispatch.","Add a type guard in the preload/renderer layer that rejects payloads with empty required fields before they reach IPC.","Log args at the rendererReq entry to confirm what was actually sent vs. what the handler expected."],"exampleFix":"// before\nelectron.request({action: 'saveFile', fileObject: {path: ''}, data: xml});\n\n// after\nfunction assertStr(v, name) { if (typeof v !== 'string' || !v) throw new TypeError('missing ' + name); }\nassertStr(fileObject.path, 'fileObject.path');\nelectron.request({action: 'saveFile', fileObject, data: xml});","handlingStrategy":"type-guard","validationCode":"function reqStrLocal(v, name) {\n\tif (typeof v !== 'string' || v.length === 0) throw new TypeError('missing string ' + name);\n\treturn v;\n}\nreqStrLocal(fileObject.path, 'fileObject.path');","typeGuard":"const isNonEmptyString = (v) => typeof v === 'string' && v.length > 0;","tryCatchPattern":"try { reqStr(args.path, 'path'); }\ncatch (e) {\n\tif (/^bad arg:/.test(e.message)) { /* surface a user-facing field error */ return; }\n\tthrow e;\n}","preventionTips":["Centralise a single isNonEmptyString helper in the renderer and reuse it on every IPC payload.","Reject malformed payloads at the preload boundary so the main process never sees them.","Include the offending field name in user-facing error UI."],"tags":["ipc","validation","renderer","argument"],"backgroundTag":null,"analyzedSha":"403a2cb79f431db13a395f033b67eeebc1631754","analyzedAt":"2026-08-13T00:15:02.468Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}