iOfficeAI/OfficeCLI · error · OfficeCliError
${r.stderr || r.stdout}
Error message
${r.stderr || r.stdout} What it means
Thrown by Document._start() (officecli open) when the resident-startup spawn returns a non-zero exit. The message is the CLI's own stderr (or stdout), so it carries officecli's reason verbatim. _start only spawns when no live resident already serves the file (serves() is a real liveness probe), so this is a genuine failure to bring the resident up.
Source
Thrown at sdk/node/index.js:464
constructor(filePath, binary = 'officecli', timeoutMs = 30000) {
// Canonical (Windows 8.3-expanded) so the pipe name AND the serves() path
// comparison both match what the resident reports.
this.path = canonicalPath(filePath);
this.bin = resolveBinary(binary);
this.timeout = timeoutMs; // connect timeout (ms); the reply read blocks
const [main, ping] = pipePaths(this.path);
this._main = main;
this._ping = ping;
this._restarting = null; // in-flight dead-resident restart (serializes callers)
}
async _start() {
// Reuse a resident already serving this file (no spawn). serves() is a real
// liveness probe (ping + path match), so a stale/dead socket falls through
// to `officecli open`, which replaces it via TryConnect.
if (await serves(this._ping, this.path)) return;
const r = runCli(this.bin, ['open', this.path]);
if (r.status !== 0) throw new OfficeCliError(r.status == null ? -1 : r.status, r.stderr || r.stdout);
}
async _cmd(command, args, props, asJson = true, timeoutMs) {
const req = { Command: command, Json: asJson };
if (args) req.Args = strMap(args);
if (props !== null && props !== undefined) req.Props = strMap(props);
const t = timeoutMs == null ? this.timeout : timeoutMs;
try {
return await rpc(this._main, req, t, BUSY_MAX_RETRIES);
} catch (e) {
if (!(e instanceof OfficeCliError)) throw e;
// Delivery failed. Use the -ping pipe to tell DEAD from BUSY:
// • ALIVE but main pipe unresponsive → do NOT bypass it (a second writer
// racing the live resident loses data on its save). Re-raise.
// • DEAD (crashed / stale socket) → restart with one `officecli open`
// and retry ONCE. Safe across reads and mutations.
if (await this.alive()) throw e;
// Serialize the restart across concurrent callers sharing this Document soView on GitHub (pinned to 1ced45e900)
Solutions
- Read the embedded stderr — it states officecli's exact reason (e.g. file_locked, corrupt, unsupported format).
- For a lock: close the other holder (Excel or another officecli resident) then retry, or call oc.open after releasing it.
- For a corrupt/unrecognized file: open the correct source file or recreate it.
- If a stale lock persists, remove the lock file (officecli's lock location, per the error) and retry.
Example fix
// before: oc.open('report.xlsx') -> [exit N] <officecli stderr: file_locked>
// after: release the other holder, then open
await otherDoc.close();
const doc = await oc.open('report.xlsx'); Defensive patterns
Strategy: validation
Validate before calling
// Pre-check the file isn't locked by another holder before open()
const fs = require('fs');
function writable(filePath) {
try { const fd = fs.openSync(filePath, 'r+'); fs.closeSync(fd); return true; }
catch { return false; } // absent or locked
} Try / catch
// Surface officecli's own reason, then recover by releasing the holder
try { await oc.open(filePath); }
catch (e) {
if (/file_locked|lock/i.test(e.message)) { await releaseHolder(); await oc.open(filePath); }
else throw e;
} Prevention
- Always close() a Document handle in a finally block to avoid orphaned locks.
- Don't keep the same file open in Excel/another resident while the SDK opens it.
- Read the embedded stderr to distinguish file_locked from corrupt/unsupported.
When it happens
Trigger: The target file is locked by another process/instance (file_locked); the file is corrupt or an unrecognized format; the path is invalid/unwritable; officecli open rejects the document for a format-specific reason; a stale lockfile blocks open.
Common situations: The same document is open in Excel/another officecli resident; a previous resident crashed leaving a lock; opening a non-Office file by mistake; read-only directory.
Related errors
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/a447c64c79209ad4.
Report an issue: GitHub.