affaan-m/ECC · error · ValueError

Receipt output already exists

Error message

Receipt output already exists: {output}

What it means

ingest_assets enforces exclusive receipt creation: before doing any work it checks whether the target receipt file already exists and raises if so. Receipts are append-only artifacts of an ingestion run and are never overwritten, so a fresh output path is required for every run.

Solutions

  1. Delete or move the existing receipt, or (preferred) choose a new output path for the new run.
  2. Use unique names per run, e.g. include a timestamp or run id: receipt-2026-09-16T10-30.json.
  3. Check output.exists() before invoking ingest_assets in scripts.
  4. Run ingest from a consistent working directory or pass absolute output paths to avoid accidental collisions.

Example fix

# before
receipt = ingest_assets('config.json', 'receipt.json')  # second run
# after
from datetime import datetime
receipt = ingest_assets('config.json', f"receipt-{datetime.now().isoformat(timespec='seconds')}.json")
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
out = Path('receipt.json')
assert not out.exists(), 'pick a new receipt path'

Try / catch

try:
    ingest_assets(cfg, out_path)
except ValueError as e:
    if 'already exists' in str(e):
        out_path = unique_receipt_name()  # e.g. timestamped
        ingest_assets(cfg, out_path)
    else:
        raise

Prevention

When it happens

Trigger: Calling ingest_assets(config_path, out_receipt) where out_receipt resolves to an existing file (from a previous run, a manual copy, or an unintended path resolution); running the same command twice without changing the output name.

Common situations: Re-running a pipeline step after a partial failure while reusing the same receipt name; scripts hardcoding 'receipt.json' as output; running ingest from a different working directory so the relative out_receipt path resolves onto an existing file.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/e87381c356ba06ae. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/assets.py:187

    if request is None:
        raise ValueError('Asset request_id/modality does not match the bundle')
    result = dict(request_id=request_id, **{key: request[key] for key in _TASTE_FIELDS})
    if verify:
        if any(asset.get(key) != value for key, value in result.items()):
            raise ValueError('Asset taste lineage differs from its bundle request')
    elif any(key in asset for key in _TASTE_FIELDS):
        raise ValueError('Taste fields are derived from the bundle, not supplied')
    return result


def ingest_assets(config_path: str | Path, out_receipt: str | Path) -> dict[str, Any]:
    """Bind local assets/provenance/lineage; write a new receipt, never overwrite."""
    config_file = _path(config_path, Path.cwd())
    config = _load(config_file)
    base = config_file.parent
    output = _path(out_receipt, Path.cwd())
    if output.exists():
        raise ValueError(f'Receipt output already exists: {output}')
    binding, requests = (_bundle(config['bundle_dir'], base, False)
                         if 'bundle_dir' in config else (None, {}))
    records = []
    for asset in _assets(config.get('assets')):
        record = {key: asset[key] for key in ('id', 'modality', 'origin')}
        record.update(_taste(asset, requests, False))
        record.update(_fingerprint(_path(asset.get('path'), base), asset['modality']))
        provenance = _provenance(asset, base, False)
        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

View on GitHub (pinned to 8321021c54)