affaan-m/ECC · error · RuntimeError

placement readback mismatch

Error message

placement {event['id']} readback mismatch: {actual!r}

What it means

This is tasteforge's post-write verification: the clip's actual start/end/duration/enabled state read back from Resolve must exactly equal the planned values. Any divergence (Resolve adjusted in/out points, disabled the clip, changed duration) throws with the full actual dict so you can see exactly what differed.

Solutions

  1. Compare the printed actual dict against expected to find the differing field (usually start/end off-by-one)
  2. Re-verify source_end_mode on this Resolve host and pass the correct convention
  3. Check the asset truly contains the requested frames (no auto-trim)
  4. Confirm target timeline fps matches the placement fps before applying

Example fix

// before
apply_placements(..., source_end_mode="inclusive")  # host is exclusive; end off by 1
// after
apply_placements(..., source_end_mode="exclusive")  # verified convention for this host
Defensive patterns

Strategy: try-catch

Validate before calling

expected_frames = end - start
assert probe(asset).get("frames", 0) >= expected_frames, "asset would be auto-trimmed"
assert _fps(timeline.GetSetting("timelineFrameRate")) == _fps(fps), "fps mismatch"

Type guard

def readback_matches(actual: dict, expected: dict) -> bool:
    return all(actual.get(k) == v for k, v in expected.items())

Try / catch

try:
    apply_placements(..., source_end_mode=MODE)
except RuntimeError as exc:
    if "readback mismatch" in str(exc):
        print(exc)  # actual dict shows the off-by-one or disabled field
    raise

Prevention

When it happens

Trigger: Resolve snapping/clamping clip in/out to track or source bounds; fps or frame-rounding differences shifting start/end by a frame; GetClipEnabled returning False; source_end_mode convention wrong so expected end is off by one frame.

Common situations: Host endpoint convention (inclusive vs exclusive) not verified for this Resolve version; asset shorter than requested causing auto-trim; timeline frame-rate mismatch silently re-timed the clip; conflicting project-level 'use dynamic trim' settings.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/resolve.py:228

        "duration": item.GetDuration(),
        "enabled": item.GetClipEnabled(),
        "track": track,
        "opacity": item.GetProperty("Opacity"),
        "composite": item.GetProperty("CompositeMode"),
        "path": _path(item),
    }
    expected = {
        "start": event["record_frame"],
        "end": event["record_frame"] + event["frames"],
        "duration": event["frames"],
        "enabled": True,
        "track": track,
        "opacity": event["opacity"],
        "composite": event["composite"],
        "path": event["asset"],
    }
    if actual != expected:
        raise RuntimeError(f"placement {event['id']} readback mismatch: {actual!r}")
    return actual


def apply_placements(
    timeline,
    media_pool,
    placements,
    *,
    source_timeline,
    source_end_mode,
    fps,
    base_track_count,
    probe=probe_asset,
):
    """Append and verify overlays; returns an in-memory placement receipt only.

    This does not save/export/render a project. Supply the selected target's
    media pool. Existing overlay tracks must be empty; base tracks are preserved.

View on GitHub (pinned to 8321021c54)