# How OfficeCLI Ensures Data Integrity During Batch Operations

> OfficeCLI ensures data integrity during batch operations with deferred saving, atomic execution, and detailed error tracking preventing partial updates. Learn how iOfficeAI OfficeCLI protects your data.

- Repository: [OfficeAI/OfficeCLI](https://github.com/iofficeai/OfficeCLI)
- Tags: internals
- Published: 2026-07-25

---

**OfficeCLI guarantees data integrity during batch operations through deferred document saving, atomic all-or-nothing execution by default, and comprehensive per-item error tracking that prevents partial updates from persisting to disk.**

The [iOfficeAI/OfficeCLI](https://github.com/iOfficeAI/OfficeCLI) repository provides a robust command-line interface and .NET SDK for automating Microsoft Office documents. When executing multiple commands via JSON batches, the tool implements a protective pipeline to ensure data integrity, prevent document corruption, and avoid expensive re-serialization operations.

## Deferred Saving and Single Write Semantics

OfficeCLI prevents the **O(N²) re-serialization** problem through a deferred saving mechanism. Before processing begins, the `RunNonResidentBatch` method sets the handler's `DeferSave` flag to `true` in [`src/officecli/CommandBuilder.Batch.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/CommandBuilder.Batch.cs) (lines 14-15).

This flag instructs the underlying document handler to accumulate all changes in memory rather than writing to disk after each individual command. The document is serialized and written exactly once after all batch items complete successfully, eliminating the risk of partial writes leaving the file in an inconsistent state.

## Atomic Execution and Transaction Safety

By default, batch operations are **atomic**—they follow an all-or-nothing semantics. The `batchStopOpt` logic in [`src/officecli/CommandBuilder.Batch.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/CommandBuilder.Batch.cs) (lines 30-38) ensures that if any single command fails, the entire batch is rolled back and the exit code indicates failure, leaving the original document untouched.

You can modify this behavior using command-line flags:

- **`--best-effort`** – Switches to a partial-apply mode where successful commands persist and failures are reported individually.
- **`--stop-on-error`** – Forces immediate termination at the first failure, handled by the `stopOnError` flag logic (lines 58-77), preventing subsequent commands from executing on potentially corrupted state.

## Granular Error Handling and Per-Item Capture

Each command in a batch is wrapped in a `try / catch` block within the `ApplyBatchItems` loop ([`src/officecli/CommandBuilder.Batch.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/CommandBuilder.Batch.cs), lines 55-78). For every item processed, OfficeCLI generates a `BatchResult` object that records:

- The success or failure status
- Output values
- Specific error codes

This granular tracking allows callers to inspect exactly which items failed without guessing, while the deferred save mechanism ensures those failures never reach the document on disk.

Additionally, the pipeline captures **unrecognized LaTeX diagnostics** after each item (lines 78-96). Any LaTeX warnings emitted by the underlying handler are collected and returned to the caller, preventing silent loss of warning information that might indicate data integrity issues.

## Conflict Prevention in Resident Mode

When operating with a **resident server** that keeps documents open in memory, OfficeCLI prevents file handle conflicts through the `skipResidentOnlyCommands` check ([`src/officecli/CommandBuilder.Batch.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/CommandBuilder.Batch.cs), lines 59-66). This logic identifies commands such as `open` and `close` that would attempt to re-open or close an already-managed document handle, silently skipping them to prevent access violations and corruption.

The resident mode components in [`src/officecli/ResidentServer.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/ResidentServer.cs) and [`src/officecli/ResidentClient.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/ResidentClient.cs) coordinate with the batch engine to maintain consistent state without redundant file operations.

## Strict Input Validation

Before any document mutation occurs, the `BatchItemConverter` class in [`src/officecli/BatchTypes.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/BatchTypes.cs) (lines 67-99) validates the incoming JSON payload. This converter tolerates both modern object-style and legacy array-style `["key=value"]` property formats, rejecting malformed inputs early with clear error messages.

By enforcing a strict schema on the `BatchItem` data model, OfficeCLI ensures that corrupted or malformed commands never reach the execution stage, protecting the document from invalid mutations.

## Practical Implementation Examples

### Running an Atomic Batch via CLI

Create a JSON batch file and execute it with default atomic semantics:

```bash
cat > batch.json <<'EOF'
[
  {"command":"add","parent":"/slide[1]","type":"shape","props":{"text":"Hello","x":"1cm","y":"2cm"}},
  {"command":"set","path":"/slide[1]/shape[1]","props":{"bold":"true"}},
  {"command":"remove","path":"/slide[2]/shape[3]"}
]
EOF

officecli batch myPresentation.pptx --input batch.json

```

*If any command fails, the whole batch aborts and `myPresentation.pptx` remains unchanged.*

### Best-Effort Mode for Partial Application

To apply successful commands while logging failures:

```bash
officecli batch myPresentation.pptx --input batch.json --best-effort

```

### Strict Stop-on-Error Mode

To halt immediately at the first error:

```bash
officecli batch myPresentation.pptx --input batch.json --stop-on-error

```

### Programmatic Batch Execution with the .NET SDK

```csharp
using OfficeCli;
using System.Collections.Generic;

var items = new List<BatchItem>
{
    new BatchItem { Command = "add", Parent = "/slide[1]", Type = "shape",
                    Props = new Dictionary<string, string>{ {"text","Hello"}, {"x","1cm"}, {"y","2cm"} } },
    new BatchItem { Command = "set", Path = "/slide[1]/shape[1]",
                    Props = new Dictionary<string, string>{ {"bold","true"} } },
    new BatchItem { Command = "remove", Path = "/slide[2]/shape[3]" }
};

var doc = await OfficeCli.SDK.open("myPresentation.pptx");

// Execute with atomic semantics (StopOnError = false maintains atomicity; true creates stop-on-error behavior)
var results = await doc.batch(items, new BatchOptions { StopOnError = false, Force = false });

foreach (var r in results)
    Console.WriteLine($"{r.Index}: {(r.Success ? "OK" : "FAIL")} – {r.Output}");

```

The SDK respects the same `DeferSave` and atomic logic as the CLI, ensuring data integrity whether used interactively or programmatically.

## Summary

- **Deferred saving** writes the document only once after all commands complete, preventing partial updates and O(N²) serialization costs.
- **Atomic-by-default execution** ensures all commands succeed or none persist, with `--best-effort` and `--stop-on-error` providing alternative strategies.
- **Per-item error capture** via `BatchResult` objects provides granular failure diagnostics without corrupting the document.
- **Resident mode safeguards** skip conflicting `open` and `close` commands to prevent file handle corruption.
- **Strict JSON validation** through `BatchItemConverter` rejects malformed payloads before they reach the document handlers.

## Frequently Asked Questions

### What happens if one command in a batch fails by default?

By default, OfficeCLI uses atomic execution. If any command throws an exception, the entire batch is rolled back according to the logic in [`src/officecli/CommandBuilder.Batch.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/CommandBuilder.Batch.cs), the document remains unchanged on disk, and the CLI returns a failure exit code.

### How does deferred saving improve both performance and integrity?

The `DeferSave` flag accumulates mutations in memory and performs a single write operation at the end of the batch. This eliminates the risk of intermediate save states corrupting the file if a later command fails, while also avoiding the performance penalty of re-serializing the entire document after every individual command.

### Can I process batch commands while a document is open in resident mode?

Yes. When a resident server holds the document open, the batch engine automatically skips `open` and `close` commands via the `skipResidentOnlyCommands` check (lines 59-66), preventing file handle conflicts while allowing other mutations to proceed safely against the in-memory document.

### What is the difference between `--best-effort` and `--stop-on-error`?

`--best-effort` switches the batch from atomic to partial-apply mode, executing all commands that can succeed and reporting failures for those that cannot. `--stop-on-error` maintains atomic semantics but aborts immediately upon the first failure, ensuring no subsequent commands execute on potentially invalid state.