{"record":{"id":"201234c065d70a3a","repo":"affaan-m/ECC","slug":"cannot-create-exclusive-receipt-output","errorCode":null,"errorMessage":"Cannot create exclusive receipt: {output}","messagePattern":"Cannot create exclusive receipt: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/assets.py","lineNumber":214,"sourceCode":"        if provenance is not None:\n            record['provider_provenance'] = provenance\n        records.append(record)\n    inputs = config.get('input_artifacts', [])\n    if not isinstance(inputs, list):\n        raise ValueError('input_artifacts must be a list of local paths')\n    receipt = dict(schema=SCHEMA, provider_calls=0, provider_execution=False,\n                   assets=records, input_artifacts=[_fingerprint(_path(p, base)) for p in inputs])\n    if binding is not None:\n        receipt['bundle_receipt'] = binding\n    if 'genre_spec' in config:\n        receipt['genre_spec'] = _fingerprint(_path(config['genre_spec'], base))\n    # All inputs already exist, so the output-exists gate also prevents collisions.\n    try:\n        with output.open('x', encoding='utf-8') as stream:\n            json.dump(receipt, stream, indent=2, sort_keys=True)\n            stream.write('\\n')\n    except OSError as exc:\n        raise ValueError(f'Cannot create exclusive receipt: {output}') from exc\n    return receipt\n\n\ndef validate_assets(receipt_path: str | Path) -> dict[str, Any]:\n    \"\"\"Re-hash every bound file and validate receipt semantics; no remote calls.\"\"\"\n    path = _path(receipt_path, Path.cwd())\n    receipt = _load(path)\n    if receipt.get('schema') != SCHEMA:\n        raise ValueError('Unsupported asset receipt schema')\n    if type(receipt.get('provider_calls')) is not int or receipt['provider_calls'] != 0:\n        raise ValueError('Local ingestion must have zero provider calls')\n    if receipt.get('provider_execution') is not False:\n        raise ValueError('Local ingestion cannot claim provider execution')\n    _, requests = (_bundle(receipt['bundle_receipt'], path.parent, True)\n                   if 'bundle_receipt' in receipt else (None, {}))\n    for asset in _assets(receipt.get('assets')):\n        _taste(asset, requests, True)\n        _verify_binding(asset, path.parent, asset['modality'])","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/assets.py#L196-L232","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nreceipt = ingest_assets('config.json', 'out/receipt.json')  # out/ missing\n# after\nfrom pathlib import Path\nPath('out').mkdir(parents=True, exist_ok=True)\nreceipt = ingest_assets('config.json', 'out/receipt.json')","handlingStrategy":"try-catch","validationCode":"from pathlib import Path\nout = Path('out/receipt.json')\nout.parent.mkdir(parents=True, exist_ok=True)\nassert not out.exists() and os.access(out.parent, os.W_OK)","typeGuard":null,"tryCatchPattern":"try:\n    ingest_assets(cfg, out_path)\nexcept ValueError as e:\n    if 'Cannot create exclusive receipt' in str(e):\n        check_permissions_and_disk(out_path); use_unique_path_and_retry()\n    else:\n        raise","preventionTips":["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."],"tags":["filesystem","io-error","exclusive-write","race-condition"],"backgroundTag":"file-write-failed","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}