{"record":{"id":"a447c64c79209ad4","repo":"iOfficeAI/OfficeCLI","slug":"r-stderr-r-stdout","errorCode":null,"errorMessage":"${r.stderr || r.stdout}","messagePattern":"\\$\\{r\\.stderr \\|\\| r\\.stdout\\}","errorType":"error_code","errorClass":"OfficeCliError","httpStatus":null,"severity":"error","filePath":"sdk/node/index.js","lineNumber":464,"sourceCode":"  constructor(filePath, binary = 'officecli', timeoutMs = 30000) {\n    // Canonical (Windows 8.3-expanded) so the pipe name AND the serves() path\n    // comparison both match what the resident reports.\n    this.path = canonicalPath(filePath);\n    this.bin = resolveBinary(binary);\n    this.timeout = timeoutMs; // connect timeout (ms); the reply read blocks\n    const [main, ping] = pipePaths(this.path);\n    this._main = main;\n    this._ping = ping;\n    this._restarting = null; // in-flight dead-resident restart (serializes callers)\n  }\n\n  async _start() {\n    // Reuse a resident already serving this file (no spawn). serves() is a real\n    // liveness probe (ping + path match), so a stale/dead socket falls through\n    // to `officecli open`, which replaces it via TryConnect.\n    if (await serves(this._ping, this.path)) return;\n    const r = runCli(this.bin, ['open', this.path]);\n    if (r.status !== 0) throw new OfficeCliError(r.status == null ? -1 : r.status, r.stderr || r.stdout);\n  }\n\n  async _cmd(command, args, props, asJson = true, timeoutMs) {\n    const req = { Command: command, Json: asJson };\n    if (args) req.Args = strMap(args);\n    if (props !== null && props !== undefined) req.Props = strMap(props);\n    const t = timeoutMs == null ? this.timeout : timeoutMs;\n    try {\n      return await rpc(this._main, req, t, BUSY_MAX_RETRIES);\n    } catch (e) {\n      if (!(e instanceof OfficeCliError)) throw e;\n      // Delivery failed. Use the -ping pipe to tell DEAD from BUSY:\n      //   • ALIVE but main pipe unresponsive → do NOT bypass it (a second writer\n      //     racing the live resident loses data on its save). Re-raise.\n      //   • DEAD (crashed / stale socket) → restart with one `officecli open`\n      //     and retry ONCE. Safe across reads and mutations.\n      if (await this.alive()) throw e;\n      // Serialize the restart across concurrent callers sharing this Document so","sourceCodeStart":446,"sourceCodeEnd":482,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/sdk/node/index.js#L446-L482","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: oc.open('report.xlsx') -> [exit N] <officecli stderr: file_locked>\n// after: release the other holder, then open\nawait otherDoc.close();\nconst doc = await oc.open('report.xlsx');","handlingStrategy":"validation","validationCode":"// Pre-check the file isn't locked by another holder before open()\nconst fs = require('fs');\nfunction writable(filePath) {\n  try { const fd = fs.openSync(filePath, 'r+'); fs.closeSync(fd); return true; }\n  catch { return false; } // absent or locked\n}","typeGuard":null,"tryCatchPattern":"// Surface officecli's own reason, then recover by releasing the holder\ntry { await oc.open(filePath); }\ncatch (e) {\n  if (/file_locked|lock/i.test(e.message)) { await releaseHolder(); await oc.open(filePath); }\n  else throw e;\n}","preventionTips":["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."],"tags":["bootstrap","resident","open","file-lock","format"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}