# Complete Guide to Transaction Error Codes in Claude‑Obsidian

> Master Claude-Obsidian transaction error codes. Understand 23 specific errors across four exception classes to diagnose and resolve issues from invalid paths to unsafe rollbacks.

- Repository: [Agrici.Daniel/claude-obsidian](https://github.com/AgriciDaniel/claude-obsidian)
- Tags: deep-dive
- Published: 2026-08-29

---

**Claude‑Obsidian defines 23 specific string error codes across four exception classes—`TransactionError`, `TransactionValidationError`, `TransactionConflict`, and `TransactionRecoveryError`—to identify exact failure points ranging from invalid file paths to unsafe rollback conditions.**

The transaction system in `AgriciDaniel/claude-obsidian` enforces strict safety guarantees when modifying Obsidian vaults. Located in [`claude_obsidian/transaction.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/transaction.py), the implementation raises granular transaction error codes that allow callers to distinguish between validation failures, runtime conflicts, and recovery errors without parsing ambiguous log messages.

## Exception Hierarchy and Exit Codes

All transaction failures in claude-obsidian inherit from a base exception class mapped to specific process exit codes.

**`TransactionError`** serves as the abstract base for all transaction-related failures and returns **exit code 1**.

**`TransactionValidationError`** signals pre-condition violations before any vault modification occurs and returns **exit code 2**. This covers path validation, identity checks, and platform compatibility.

**`TransactionConflict`** indicates that a file changed while being inspected and returns **exit code 75** (tempfail). This is raised in [`claude_obsidian/transaction.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/transaction.py) when `_safe_file_state` detects a race condition between two `stat` calls (lines 100–106).

**`TransactionRecoveryError`** indicates that a transaction rollback cannot be performed safely and returns **exit code 3**. This is raised when `_confined_vault_unlink` detects that a rollback target’s content or identity changed since it was recorded (lines 21–29).

## Path Validation Error Codes

The system validates every write path through `_normalize_vault_path` and `_assert_portable_write_path`, emitting specific codes for each failure mode.

- **`INVALID_WRITE_PATH`**: Raised when the path is empty, contains control characters, backslashes, or is absolute (lines 58–63).
- **`NONCANONICAL_WRITE_PATH`**: Raised when the path is not in normalized POSIX form (lines 70–73).
- **`NONCANONICAL_UNICODE_PATH`**: Raised when the path is not NFC-normalized Unicode (lines 75–77).
- **`WRITE_PATH_TOO_LONG`**: Raised when the UTF-8 byte length exceeds the portable limit (lines 80–84).
- **`UNPORTABLE_WRITE_PATH`**: Raised when the path contains characters unsafe on portable filesystems (`:<>|?*"`), ends with a dot or space, or matches a reserved device name (lines 96–105).
- **`SYMLINK_WRITE_PATH`**: Raised by `_assert_portable_write_path` when a write would traverse a symlink or junction (lines 112–115).

Vault directory constraints trigger additional validation codes:

- **`CASEFOLD_PATH_ALIAS`**: Raised by `_assert_no_portable_vault_leaf_alias_at` when a sibling entry aliases the target when case-folded (lines 86–99).
- **`VAULT_DIRECTORY_LIMIT`**: Raised when a directory contains more than `MAX_PORTABLE_SIBLING_ENTRIES` entries (lines 78–83).
- **`INVALID_VAULT_ROOT_NAME`**: Raised when the vault root name violates NFC, length, or control-character constraints (lines 64–74).

## Operation and Identity Error Codes

Transaction metadata and vault identity verification use distinct error codes to signal contract violations.

- **`INVALID_OPERATION_ID`**: Raised by `safe_operation_id` when the operation ID is missing or contains unsafe characters (lines 38–49).
- **`UNSAFE_VAULT_IDENTITY`**: Raised by `_vault_object_identity` when the system cannot reliably pin a vault directory (lines 50–52).
- **`VAULT_NOT_DIRECTORY`**: Raised when the vault path exists but is not a directory (lines 55–58).
- **`VAULT_IDENTITY_CHANGED`**: Raised when the vault appeared or disappeared while its identity was being read (lines 63–66).
- **`UNSAFE_VAULT_PATH`**: General code for any situation where a path cannot be safely inspected due to symlinks, non-directory parents, or permission errors (e.g., `_safe_vault_path` lines 31–34).

## File Size and Content Error Codes

Read operations and transaction size limits emit specific codes to prevent unbounded memory consumption.

- **`INVALID_READ_LIMIT`**: Raised by `_read_vault_regular` when the `limit` argument is not a positive integer (lines 38–41).
- **`VAULT_FILE_MISSING`**: Raised when the requested vault file does not exist and `missing_ok=False` (lines 62–66).
- **`VAULT_FILE_TOO_LARGE`**: Raised when a vault file exceeds the allowed read limit (lines 96–99).
- **`TRANSACTION_FILE_TOO_LARGE`**: Raised by `_safe_file_state` when a file size exceeds `MAX_TRANSACTION_FILE_BYTES` during a transaction (lines 86–89).

## Conflict and Recovery Error Codes

Runtime race conditions and rollback failures use dedicated exception types.

- **`FILE_CHANGED_DURING_READ`**: A `TransactionConflict` raised by `_safe_file_state` when a file changes between two `stat` calls while being read (lines 100–106).
- **`ROLLBACK_TARGET_CHANGED`**: A `TransactionRecoveryError` raised by `_confined_vault_unlink` when the rollback target’s content, type, or identity changed since it was recorded (lines 21–29).

## Platform and Runtime Error Codes

Platform compatibility and runtime environment issues are detected before transaction execution.

- **`UNSUPPORTED_PLATFORM`**: Raised by `_require_write_platform` when the host platform lacks required directory-descriptor confinement, such as native Windows (lines 16–18).
- **`UNSAFE_RUNTIME_PATH`**: Raised by `_safe_directory` when runtime directory creation or inspection fails, such as when the system cannot create a safe parent directory (lines 84–96).
- **`UNSAFE_LOCK_PATH`**: Raised via `TransactionValidationError` in lock-related functions like `_require_lock_dirfd_support` when lock-directory handling fails (lines 66–73).

## Handling Transaction Errors in Python

Client code should catch specific exception types to implement appropriate retry or cleanup logic. All error codes are accessible via the `.code` attribute on exception instances.

```python
from claude_obsidian.transaction import (
    TransactionValidationError,
    TransactionConflict,
    TransactionRecoveryError
)

def safe_vault_write(operation_id, path, content):
    try:
        # Attempt transaction

        pass
    except TransactionValidationError as e:
        # Handle pre-condition failures (exit code 2)

        if e.code == "INVALID_WRITE_PATH":
            print(f"Path validation failed: {e}")
        elif e.code == "UNSUPPORTED_PLATFORM":
            print("Platform lacks required confinement support")
        raise
    except TransactionConflict as e:
        # Handle race conditions (exit code 75)

        if e.code == "FILE_CHANGED_DURING_READ":
            print("File modified during inspection; retry suggested")
        raise
    except TransactionRecoveryError as e:
        # Handle rollback failures (exit code 3)

        if e.code == "ROLLBACK_TARGET_CHANGED":
            print("Rollback target modified; manual intervention required")
        raise

```

The test suite in [`tests/test_transaction.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/tests/test_transaction.py) exercises each error condition to ensure codes are emitted correctly, while [`tests/test_vault_ops.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/tests/test_vault_ops.py) and [`tests/test_windows_compat.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/tests/test_windows_compat.py) verify platform-specific behavior.

## Summary

- **Four exception classes** handle all transaction failures: `TransactionError` (base), `TransactionValidationError` (exit code 2), `TransactionConflict` (exit code 75), and `TransactionRecoveryError` (exit code 3).
- **23 string error codes** provide granular failure identification, ranging from `INVALID_OPERATION_ID` to `ROLLBACK_TARGET_CHANGED`.
- **Validation errors** dominate the catalog, covering path normalization (`NONCANONICAL_WRITE_PATH`), Unicode safety (`NONCANONICAL_UNICODE_PATH`), and vault identity (`UNSAFE_VAULT_IDENTITY`).
- **Conflict detection** uses `FILE_CHANGED_DURING_READ` to signal race conditions during file inspection.
- **Platform safety** is enforced via `UNSUPPORTED_PLATFORM` for environments lacking directory-descriptor confinement.

## Frequently Asked Questions

### What is the difference between `TransactionValidationError` and `TransactionConflict`?

`TransactionValidationError` (exit code 2) is raised before any filesystem modifications occur, covering issues like invalid paths or unsupported platforms. `TransactionConflict` (exit code 75) is raised during active file inspection when `_safe_file_state` detects that a file changed between consecutive `stat` calls, indicating a concurrent modification.

### Which error code indicates a file changed during reading?

The `FILE_CHANGED_DURING_READ` code is raised as a `TransactionConflict` by the `_safe_file_state` function in [`claude_obsidian/transaction.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/transaction.py) (lines 100–106) when the system detects a race condition during file inspection.

### How do I handle platform-specific errors on Windows?

Catch `TransactionValidationError` with code `UNSUPPORTED_PLATFORM`, which is raised by `_require_write_platform` (lines 16–18) when the host lacks directory-descriptor confinement. Native Windows without WSL typically triggers this code, requiring you to implement alternative safety mechanisms or abort the transaction.

### What exit code is returned for rollback failures?

`TransactionRecoveryError` returns **exit code 3** when a rollback cannot be performed safely. The specific `ROLLBACK_TARGET_CHANGED` code indicates that the target file’s content, type, or identity changed since the transaction recorded its state, making automatic recovery impossible.