Skip to content

Windows receipt store uses raw sha256 receipt IDs as filenames, causing os error 87 #74

Description

@xyjk0511

Summary

On Windows, the receipt store appears to use raw receipt IDs such as sha256:... directly as filenames. That breaks receipt persistence because : is not allowed in Windows filenames.

Observed symptom:

receipt store is unreadable: 参数错误。 (os error 87)

This makes receipt-backed runx skill / harness flows fail on Windows even when the skill itself is valid.

Public repro

The repro uses the public hello-world example skill and asserts that a basic receipt-backed skill run should:

  1. exit successfully
  2. seal a receipt
  3. create at least one receipt JSON file in the selected receipt store

Today that test fails on Windows.

Environment

  • OS: Windows
  • CLI observed: runx-cli 0.6.1

Reproduction

Example command that reproduces locally on Windows:

runx skill .\hello-world --input 'message=hello' --receipt-dir .\.tmp\receipts --json

Observed output:

{
  "error": {
    "code": "skill_error",
    "message": "receipt store is unreadable: 参数错误。 (os error 87)"
  },
  "status": "failure"
}

Root cause hypothesis

crates/runx-runtime/src/receipts/store.rs has:

fn receipt_file_name(receipt_id: &str) -> Result<String, ReceiptStoreError> {
    if receipt_id.is_empty()
        || receipt_id == "."
        || receipt_id == ".."
        || receipt_id.contains('/')
        || receipt_id.contains('\\')
    {
        return Err(ReceiptStoreError::InvalidReceiptId {
            receipt_id: receipt_id.to_owned(),
        });
    }
    Ok(format!("{receipt_id}.json"))
}

That rejects / and \\, but it does not reject or encode :.
Because receipt IDs commonly look like sha256:..., the store ends up trying to materialize filenames like:

sha256:abc123....json

That filename is invalid on Windows.

Expected behavior

Receipt storage should work on Windows, macOS, and Linux.
The storage layer should not use raw receipt IDs as platform path components when they contain OS-invalid characters.

Suggested direction

Map receipt IDs to platform-safe filenames before writing to disk. Examples:

  • percent-encoding
  • base64url / hex encoding
  • hash-based filename with the original receipt ID stored in file contents or index metadata

Green condition

The public repro test should exit 0 on Windows and create at least one .json receipt file under .tmp/receipts/.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions