How Batch Mode in OfficeCLI Handles Multiple Operations and Error Handling

OfficeCLI forwards an array of commands as a single JSON payload to the resident process, executing them in one round-trip while isolating or aborting on failures based on the stopOnError configuration.

OfficeCLI’s Node SDK implements batch mode as a high-throughput mechanism for applying multiple spreadsheet transformations without spawning separate processes per command. By serializing operations into a structured envelope and routing them through a persistent pipe, the library minimizes latency and provides deterministic error handling policies. Understanding how the batch() method in sdk/node/index.js constructs payloads and manages transport resilience is critical for production automation workflows.

How the Batch Payload Is Constructed

The batch(items, options) method aggregates commands into a JSON object with three fields: batchJson, force, and stopOnError. The batchJson value is a stringified array where each element follows the same schema as a single send() invocation—typically containing command, path, and props keys.

According to the implementation in sdk/node/index.js (lines 19‑22), the method signature defaults force to true and accepts an optional stopOnError boolean:

{
  batchJson: JSON.stringify([
    { command: "set", path: "/Sheet1/A1", props: { text: "Hello" } },
    { command: "set", path: "/Sheet1/B2", props: { number: 123 } }
  ]),
  force: true,
  stopOnError: false
}

This structure allows the resident Office process to deserialize the entire workload before execution begins, ensuring atomic preparation of the command queue.

Single Round-Trip Execution

Once serialized, the payload travels through the private _cmd('batch', …) helper, which delegates to the low-level rpc() function. As documented in the file header (lines 5‑9), both send() and batch() utilize the same transport mechanism: writing one request line to the resident’s named pipe and awaiting a response envelope.

This architecture mirrors the CLI’s officecli batch command, eliminating the overhead of process creation for every cell update or range formatting operation. The resident maintains state across the batch, applying each command sequentially within the same workbook context.

Handling Locked Files with the Force Option

By default, batch() passes force: true, instructing the resident to apply changes even if the target file is currently locked by another application. This corresponds to the CLI’s --force flag and prevents transient lock contention from blocking automation pipelines. Developers can override this by explicitly setting force: false in the options object if strict concurrency control is required.

Error Handling Strategies

OfficeCLI distinguishes between transport-level failures (pipe disconnection, timeouts) and logical command failures (invalid cell references, type mismatches). The stopOnError flag determines how the resident handles individual command errors within the batch.

Continue on Error (stopOnError: false)

When stopOnError is omitted or set to false (the default), the resident processes the entire command list regardless of individual failures. It returns a combined envelope where the top-level success field reflects overall completion, while per-command errors populate the Stdout and Stderr fields. This mode maximizes throughput and allows post-hoc analysis of which specific indices failed.

Abort on First Failure (stopOnError: true)

Setting stopOnError: true causes the resident to terminate batch execution immediately upon encountering the first failing command. The response envelope returned at this point contains an error state, and subsequent commands in the array remain unprocessed. This strict mode is useful when operations have strict dependencies—such as inserting a row before writing to it—and partial completion would leave the workbook in an inconsistent state.

Note that the SDK surface throws OfficeCliError only when the transport itself fails (e.g., pipe connection problems or resident crash). Logical command failures remain inside the returned envelope regardless of the stopOnError setting.

Transport-Level Reliability

Both send() and batch() rely on the rpc() function defined around lines 88‑98 in sdk/node/index.js. This implementation provides:

  • Bounded connect timeout: Controlled by BUSY_CONNECT_TIMEOUT_MS to prevent indefinite hangs
  • Configurable retry logic: BUSY_MAX_RETRIES with backoff for busy pipes
  • Transparent resident restart: Automatically respawns the resident process if it dies mid-batch
  • Single retry for busy pipes: Attempts immediate reconnection before escalating

If the resident cannot be reached after exhausting retries, rpc() throws OfficeCliError, which propagates out of batch() as a rejected promise. This distinction allows calling code to catch infrastructure failures separately from application-level validation errors.

Parsing Batch Results

The raw response line returned by rpc() is parsed by parseEnvelope() (referenced but not shown in the excerpt), extracting ExitCode, Stdout, and Stderr. The batch() method returns this envelope directly, enabling inspection of per-command results when stopOnError is disabled. Developers should check result.ExitCode and parse result.Stdout to determine individual operation success within the batch array.

Practical Example: Executing Multiple Cell Updates

The following example demonstrates opening a workbook, preparing several set commands, and executing them atomically with default error isolation:

const oc = require('@officecli/sdk');

(async () => {
  // Open an existing workbook
  const doc = await oc.open('budget.xlsx');

  // Prepare several commands
  const ops = [
    { command: 'set', path: '/Sheet1/B2', props: { number: 123 } },
    { command: 'set', path: '/Sheet1/C2', props: { number: 456 } },
    { command: 'set', path: '/Sheet1/D2', props: { number: 789 } },
  ];

  // Execute them in one batch; stopOnError defaults to false
  const result = await doc.batch(ops);
  console.log('Batch envelope:', result);

  // Inspect individual outcomes via result.Stdout/Stderr
  if (result.ExitCode !== 0) {
    console.error('One or more commands failed:', result.Stderr);
  }

  await doc.close();
})();

To enforce strict sequential integrity where a failure in cell B2 prevents writing to C2 and D2, pass { stopOnError: true } as the second argument to batch().

Summary

  • Batch Mode in OfficeCLI serializes command arrays into a JSON envelope via batch(items, options) in sdk/node/index.js (lines 19‑22).
  • Single round-trip execution sends the payload through _cmd('batch', …) and rpc(), avoiding per-command process spawning (lines 5‑9).
  • Force option defaults to true, allowing writes to locked files unless explicitly disabled.
  • Error handling operates at two levels: transport failures raise OfficeCliError, while command failures respect the stopOnError flag—either collecting all errors or aborting immediately (lines 19‑21, 88‑98).
  • Result inspection requires parsing the returned envelope’s ExitCode, Stdout, and Stderr to determine per-operation success when continuing past individual failures.

Frequently Asked Questions

What happens if one command in an OfficeCLI batch fails?

When stopOnError is false (the default), the resident continues processing subsequent commands and returns a combined envelope containing all results. Individual failures appear in the Stderr or Stdout fields, allowing you to identify which array indices failed after the batch completes.

Does OfficeCLI batch mode require force=true to work with locked files?

While not strictly required, force defaults to true in the batch() method, automatically overriding file locks. If you set force: false, the batch will fail if the target workbook is open in another application, matching standard CLI behavior without the --force flag.

How does OfficeCLI handle transport failures during batch execution?

The rpc() function implements BUSY_CONNECT_TIMEOUT_MS and BUSY_MAX_RETRIES with backoff logic (lines 88‑98). If the resident pipe is unreachable after retries, rpc() throws OfficeCliError, which propagates through batch() as a rejection. This indicates infrastructure failure rather than command validation errors.

Can I mix different command types in a single OfficeCLI batch?

Yes. The batchJson array accepts heterogeneous command objects—such as set, get, insert, or delete—each with distinct path and props configurations. The resident processes them sequentially in the order provided, respecting the global stopOnError policy for the entire set.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →