jgraph/drawio-desktop · error · Error
bad arg: fileObject.path
Error message
bad arg: fileObject.path
What it means
saveFile's structural guard (src/main/electron.js:3429-3432): fileObject is null or its .path is not a string. This runs after the content check but before assertWritablePath, so a malformed fileObject never reaches fs APIs. The IPC handler already calls reqStr on fileObject.path, so this is a defence for internal callers of saveFile.
Source
Thrown at src/main/electron.js:3431
modified: stat.mtimeMs,
path: bkpPaths[i]};
}
catch (e){} // Ignore, try next prefix / no backup
}
return null;
};
async function saveFile(fileObject, data, origStat, overwrite, defEnc)
{
if (!checkFileContent(data))
{
throw new Error('Invalid file data');
}
if (fileObject == null || typeof fileObject.path !== 'string')
{
throw new Error('bad arg: fileObject.path');
}
await assertWritablePath(fileObject.path);
var retryCount = 0;
var backupCreated = false;
var bkpPath = path.join(path.dirname(fileObject.path), BKP_PREFEX + path.basename(fileObject.path) + BKP_EXT);
const oldBkpPath = path.join(path.dirname(fileObject.path), OLD_BKP_PREFEX + path.basename(fileObject.path) + BKP_EXT);
var writeEnc = defEnc || fileObject.encoding;
// Backup paths are derived siblings of fileObject.path, so they pass the
// draft/bkp carve-out — but realpath them anyway in case symlinks have
// been planted at those names.
await assertWritablePath(bkpPath);
var writeFile = async function()
{
let fh;View on GitHub (pinned to 403a2cb79f)
Solutions
- Construct fileObject as {path: <string>, encoding?: <string>} before calling saveFile.
- Route saves through the rendererReq 'saveFile' action so the IPC handler's reqStr guard catches the issue earlier.
- Add a unit test that asserts saveFile throws this exact message for null fileObject.
Example fix
// before
await saveFile({path: maybeUndefined}, data, stat, false);
// after
if (!fileObject || typeof fileObject.path !== 'string') throw new TypeError('fileObject.path required');
await saveFile(fileObject, data, stat, false); Defensive patterns
Strategy: type-guard
Validate before calling
function hasStringPath(fileObject) {
return fileObject != null && typeof fileObject.path === 'string' && fileObject.path.length > 0;
}
if (!hasStringPath(fileObject)) throw new TypeError('fileObject.path required'); Type guard
function hasStringPath(fileObject) {
return fileObject != null && typeof fileObject === 'object' &&
typeof fileObject.path === 'string' && fileObject.path.length > 0;
} Try / catch
try { await saveFile(fileObject, data, stat, false); }
catch (e) {
if (e.message === 'bad arg: fileObject.path') { /* prompt user to pick a file */ return; }
throw e;
} Prevention
- Always construct fileObject as {path: <string>} via a single factory.
- Route saves through the IPC handler so reqStr guards .path first.
- For internal saveFile callers, add a TS type or runtime contract on fileObject.
When it happens
Trigger: saveFile invoked directly (not via the IPC switch) with fileObject = null, fileObject = {}, or fileObject.path = undefined/number.
Common situations: A refactor introduced a second call site for saveFile that skipped constructing a proper fileObject; a test harness passed a partial mock.
Related errors
AI-assisted analysis of jgraph/drawio-desktop@403a2cb79f (2026-08-13).
Data as JSON: /api/errors/5b41726021c83ea3.
Report an issue: GitHub.