affaan-m/ECC · error · ValueError
Cannot create exclusive receipt
Error message
Cannot create exclusive receipt: {output} What it means
ingest_assets writes the receipt with exclusive creation (open mode 'x'); any OSError during creation or writing is re-raised as this ValueError. Because the earlier exists() gate passed, this usually means a race (file created between check and open) or a filesystem-level failure (permission, directory missing, disk full).
Solutions
- Ensure the output directory exists and is writable (mkdir -p; check permissions).
- Serialize runs or use unique output names per worker to avoid the check-then-create race.
- Retry after resolving the underlying OSError; the chained exception message contains the cause.
- Check disk space/quota if the message persists.
Example fix
# before
receipt = ingest_assets('config.json', 'out/receipt.json') # out/ missing
# after
from pathlib import Path
Path('out').mkdir(parents=True, exist_ok=True)
receipt = ingest_assets('config.json', 'out/receipt.json') Defensive patterns
Strategy: try-catch
Validate before calling
from pathlib import Path
out = Path('out/receipt.json')
out.parent.mkdir(parents=True, exist_ok=True)
assert not out.exists() and os.access(out.parent, os.W_OK) Try / catch
try:
ingest_assets(cfg, out_path)
except ValueError as e:
if 'Cannot create exclusive receipt' in str(e):
check_permissions_and_disk(out_path); use_unique_path_and_retry()
else:
raise Prevention
- Create the output directory and check writability before ingest.
- Use unique per-run output paths to avoid concurrent-writer races.
- Serialize ingestion steps in CI; never run two ingests to the same path.
When it happens
Trigger: Two processes calling ingest_assets with the same output path concurrently; output directory lacking write permission; parent directory does not exist; disk quota/full filesystem; output path resolving to a special file; Windows sharing violations.
Common situations: CI parallel jobs writing the same receipt path; running ingest in a read-only mounted directory; missing output directory after a clean step; NFS/SMB stale-lock style collisions.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- artifact byte count exceeded during reading
- artifact changed before reading
- artifact changed during reading
- capsule.lock_lost
- ECC_MEMORY_INCOMPLETE
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/201234c065d70a3a.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/assets.py:214
if provenance is not None:
record['provider_provenance'] = provenance
records.append(record)
inputs = config.get('input_artifacts', [])
if not isinstance(inputs, list):
raise ValueError('input_artifacts must be a list of local paths')
receipt = dict(schema=SCHEMA, provider_calls=0, provider_execution=False,
assets=records, input_artifacts=[_fingerprint(_path(p, base)) for p in inputs])
if binding is not None:
receipt['bundle_receipt'] = binding
if 'genre_spec' in config:
receipt['genre_spec'] = _fingerprint(_path(config['genre_spec'], base))
# All inputs already exist, so the output-exists gate also prevents collisions.
try:
with output.open('x', encoding='utf-8') as stream:
json.dump(receipt, stream, indent=2, sort_keys=True)
stream.write('\n')
except OSError as exc:
raise ValueError(f'Cannot create exclusive receipt: {output}') from exc
return receipt
def validate_assets(receipt_path: str | Path) -> dict[str, Any]:
"""Re-hash every bound file and validate receipt semantics; no remote calls."""
path = _path(receipt_path, Path.cwd())
receipt = _load(path)
if receipt.get('schema') != SCHEMA:
raise ValueError('Unsupported asset receipt schema')
if type(receipt.get('provider_calls')) is not int or receipt['provider_calls'] != 0:
raise ValueError('Local ingestion must have zero provider calls')
if receipt.get('provider_execution') is not False:
raise ValueError('Local ingestion cannot claim provider execution')
_, requests = (_bundle(receipt['bundle_receipt'], path.parent, True)
if 'bundle_receipt' in receipt else (None, {}))
for asset in _assets(receipt.get('assets')):
_taste(asset, requests, True)
_verify_binding(asset, path.parent, asset['modality'])View on GitHub (pinned to 8321021c54)