Skip to content

Malformed meta.json raises raw ValueError at 3 call sites instead of failing closed (4 red, plus a 5th routed around for months) #3140

Description

@MOES-Media

Four tests across three independent call sites assert that a corrupt or non-conforming meta.json is handled gracefully — returning None, or raising a typed domain exception. All four are red on main: each call site instead lets a raw ValueError propagate.

The failures

Node-id Job Expected Actual
tests/lanes/test_worktree_allocator.py::TestDefensiveHelpers::test_read_coordination_branch_none_on_malformed_json integration-tests-lanes None ValueError: Malformed JSON in …/meta.json: Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
tests/unit/status/test_mission_status_aggregate.py::TestLoadCoordUnavailableFailsClosed::test_corrupt_meta_fails_closed_instead_of_legacy_fallback integration-tests-core-misc (misc) MissionMetadataUnavailable ValueError: Malformed JSON in …/meta.json: Expecting value: line 1 column 63 (char 62)
tests/unit/status/test_mission_status_aggregate.py::TestLoadCoordUnavailableFailsClosed::test_non_dict_meta_fails_closed_instead_of_legacy_fallback integration-tests-core-misc (misc) MissionMetadataUnavailable ValueError: Expected JSON object in …/meta.json, got list
tests/specify_cli/cli/commands/test_charter_widen_integration.py::TestGetMissionId::test_returns_none_if_json_malformed fast-tests-cli None ValueError

Evidence

Stable — all four fail identically in two independent runs on the same SHA:

Run Trigger
30681941495 schedule, 2026-08-01T03:24:54Z
30621215287 push, 2026-07-31T09:47:27Z

Both on bb2020fea924d6e5b157974f27a7cab1a77ad259.

The shape

Three call sites — the lane worktree allocator, the mission-status aggregate, and the charter mission-id lookup — each wrap a meta.json read that is supposed to degrade gracefully, and each now surfaces the raw parse error instead. The ValueError messages are well-formed and specific (Malformed JSON in <path>, Expected JSON object in <path>, got list), which suggests a shared reader that was made stricter and now raises where it previously returned a sentinel, rather than three call sites independently losing their guards.

Check that before filing follow-ups or fixing site-by-site. If one reader changed, this is one fix. If the guards were removed independently, it is three, and test_read_coordination_branch_none_on_malformed_json's name suggests its guard was deliberate.

A fifth instance, already known and never filed

tests/agent/.../test_charter_io.py::test_get_mission_id_returns_none_when_meta_json_malformed has been carried on at least one mission's briefed "known pre-existing failures — do not chase" list. It is the same assertion shape as the fourth row above, in a different file.

That is the reason this is worth an issue rather than a shrug: the failure class is old enough to have been informally routed around by more than one piece of work, which is exactly how a defect stops being counted. Under DIR-013 a pre-existing failure gets filed rather than absorbed as accepted baseline.

Why the direction matters

Three of the four tests assert fail-closed behaviour by name (TestLoadCoordUnavailableFailsClosed, ..._fails_closed_instead_of_legacy_fallback). A raw ValueError escaping to the caller is not fail-closed — it is uncaught, and the calling surface decides what happens by accident. Whichever way this is fixed, the fix should preserve the distinction those test names are drawing: refusing to proceed is not the same as crashing.

What has not been established

  • Whether one shared reader or three separate guards changed.
  • Which commit introduced it.
  • Whether the ValueError-raising behaviour is intended and the tests are stale — possible, given the messages are deliberate and well-formed, in which case the tests need updating and the fail-closed contract needs restating somewhere durable.

Filed from a CI baseline inventory taken at bb2020fea9, which separated pre-existing reds from PR-caused ones for an unrelated mission. Of 41 distinct failing node-ids, 29 were tied to an open issue and 18 were unfiled; these 4 are one of two unfiled clusters.

Metadata

Metadata

Assignees

Labels

priority:P1High-value stabilization / bug or release confidence

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions