iOfficeAI/OfficeCLI · error · OfficeCliError

-1

-1

Error message

resident is running but the command could not be delivered (pipe busy or unresponsive); retry, or close and reopen [${e.message}]

What it means

Raised by rpc() (code -1) when the resident's pipe cannot be connected to / written within BUSY_MAX_RETRIES (3) attempts with backoff, mirroring officecli's TrySend busy-delivery policy. Because every retry happens BEFORE the command executes, re-sending is safe; this error means even the generous connect budget (30s) was exhausted. The message embeds the underlying socket error.

Source

Thrown at sdk/node/index.js:208

 * retries with backoff, then a blocking read. A retry only re-attempts the
 * connect (before the command runs), so it never double-applies a mutation. If
 * the command still can't be delivered, raise a busy/unresponsive error — never
 * fall back to touching the file directly (that would race the resident).
 *
 * `maxRetries` overrides the busy-retry count. Liveness probes (serves) pass 0
 * so a missing/stale pipe fails FAST instead of sleeping through the backoff.
 */
async function rpc(sockPath, req, connectTimeoutMs = BUSY_CONNECT_TIMEOUT_MS, maxRetries = BUSY_MAX_RETRIES) {
  const line = Buffer.from(JSON.stringify(req) + '\n', 'utf8');
  let raw = null;
  for (let attempt = 0; ; attempt++) {
    try {
      raw = await sendOnce(sockPath, line, connectTimeoutMs);
      break;
    } catch (e) {
      // Connect/socket error only — the command never ran, so a retry is safe.
      if (attempt >= maxRetries) {
        throw new OfficeCliError(
          -1,
          'resident is running but the command could not be delivered ' +
            `(pipe busy or unresponsive); retry, or close and reopen [${e.message}]`
        );
      }
      await sleep(50 * (attempt + 1)); // = TrySend's 50*(n+1)ms backoff
    }
  }
  const text = decodeLine(raw);
  if (!text.trim()) {
    // Empty/closed reply: the resident accepted the connection but closed
    // without a complete response (e.g. crashed mid-serve). We refuse to
    // re-send — the command may already have been APPLIED before the resident
    // died, so re-sending would double-apply a non-idempotent op — and raise
    // instead. _cmd's recovery then restarts a dead resident and retries once.
    throw new OfficeCliError(
      -1,
      'resident closed the connection without a response ' +

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Simply retry the call (send/batch) — the failure occurred before the command ran, so a retry cannot double-apply.
  2. Reduce concurrency against the shared resident (serialize or queue your sends) so the connect budget is not exhausted.
  3. Call doc.close() then oc.open() again to restart a resident that appears wedged.
  4. Raise the per-call timeout via the timeoutMs argument if the resident is legitimately busy for long periods.

Example fix

// before: doc.send(...) -> [exit -1] resident is running but the command could not be delivered
// after: retry idempotently with backoff
async function sendRetry(doc, item, tries = 4) {
  for (let i = 0; i < tries; i++) {
    try { return await doc.send(item); }
    catch (e) { if (e.code !== -1 || i === tries - 1) throw e; await new Promise(r => setTimeout(r, 100 * (i + 1))); }
  }
}
Defensive patterns

Strategy: retry

Try / catch

// Safe retry: the failure happens BEFORE the command runs, so re-send cannot double-apply
async function sendResilient(doc, item, { tries = 4, base = 100 } = {}) {
  for (let i = 0; ; i++) {
    try { return await doc.send(item); }
    catch (e) {
      const busy = e.code === -1 && /could not be delivered/.test(e.message);
      if (!busy || i >= tries - 1) throw e;
      await new Promise(r => setTimeout(r, base * (i + 1)));
    }
  }
}

Prevention

When it happens

Trigger: The resident is alive but saturated: a long-running command holds the serialized queue and all connect attempts time out; too many concurrent SDK clients contending for one named pipe; the OS pipe backlog is full; transient ECONNREFUSED/EAGAIN while the resident is mid-handshake.

Common situations: A large batch over a slow doc; many parallel workers sharing one resident; a resident stuck in a slow save; the pipe briefly unavailable during a restart window.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/cac109133738ad42. Report an issue: GitHub.