{"record":{"id":"d4ad4d0d7360ebad","repo":"mvanhorn/last30days-skill","slug":"label-path-has-kind-file-kind-r-expected-k","errorCode":null,"errorMessage":"{label} {path} has kind {file_kind!r}; expected {kind!r}. {remedy}","messagePattern":"(.+?) (.+?) has kind (.+?); expected (.+?)\\. (.+?)","errorType":"exception","errorClass":"HandoffContractError","httpStatus":null,"severity":"error","filePath":"skills/last30days/scripts/lib/discovery_handoff.py","lineNumber":420,"sourceCode":"        payload = json.loads(raw)\n    except json.JSONDecodeError as exc:\n        raise HandoffContractError(\n            f\"{label} {path} is not valid JSON: {exc}\"\n        ) from exc\n    if not isinstance(payload, dict):\n        raise HandoffContractError(\n            f\"{label} {path} must be a top-level JSON object, \"\n            f\"got {type(payload).__name__}.\"\n        )\n    version = payload.get(\"schema_version\")\n    if version != schema_version:\n        raise HandoffContractError(\n            f\"{label} {path} has schema version {version!r}; this \"\n            f\"build reads {schema_version!r}. {remedy}\"\n        )\n    file_kind = payload.get(\"kind\")\n    if file_kind != kind:\n        raise HandoffContractError(\n            f\"{label} {path} has kind {file_kind!r}; expected \"\n            f\"{kind!r}. {remedy}\"\n        )\n    bundle_id = str(payload.get(\"bundle_id\") or \"\")\n    if not bundle_id:\n        raise HandoffContractError(\n            f\"{label} {path} is missing its bundle_id; \"\n            f\"{missing_id_context}. {remedy}\"\n        )\n    generated_at = payload.get(\"generated_at\")\n    if not env.is_timestamp_fresh(generated_at, DISCOVERY_HANDOFF_TTL_SECONDS):\n        raise HandoffContractError(\n            f\"{label} {path} is stale (generated_at=\"\n            f\"{generated_at!r}, TTL {int(DISCOVERY_HANDOFF_TTL_SECONDS)}s): \"\n            f\"{stale_context}. {remedy}\"\n        )\n    return payload, bundle_id, generated_at\n","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/discovery_handoff.py#L402-L438","documentation":"`_parse_handoff_envelope` raises HandoffContractError when the file's `kind` field does not equal the expected discriminator (`DISCOVERY_NOMINATIONS_KIND` for `discover-nominations.json`, `DISCOVERY_PENDING_KIND` for `discover-pending.json`). The kind check exists so a structurally valid handoff file of the wrong type is never parsed as another type — e.g. a pending report renamed/placed where a bundle is expected.","triggerScenarios":"Renaming `discover-pending.json` to `discover-nominations.json` (or vice versa); a save dir carrying state from the wrong leg; a hand-crafted file copied from a different protocol artifact.","commonSituations":"Users trying to skip leg 1 by converting leg-2 output into a bundle; file juggling between save dirs; copy-paste of handoff files between protocol runs.","solutions":["Run each leg with its own flags and let the engine write the files — never rename or repurpose handoff artifacts.","Delete the wrong-kind file from the save/config dir and regenerate via the proper leg (`--discover --nominate-only` for the bundle).","Inspect `jq .kind <path>` to confirm which artifact you actually have before deciding the next leg."],"exampleFix":"# before\nmv discover-pending.json discover-nominations.json   # trying to fake leg-1 state\n# after\nrm discover-nominations.json && python3 last30days.py \"topic\" --discover --nominate-only --save-dir .","handlingStrategy":"validation","validationCode":"import json\nfrom pathlib import Path\nfrom lib import schema\n\ndef kind_matches(path: Path, expected_kind: str) -> bool:\n    try:\n        return json.loads(path.read_text(encoding=\"utf-8\")).get(\"kind\") == expected_kind\n    except (OSError, json.JSONDecodeError):\n        return False","typeGuard":null,"tryCatchPattern":"from lib import discovery_handoff\ntry:\n    bundle = discovery_handoff.load_nominations_bundle(save_dir=save_dir, config_dir=config_dir)\nexcept discovery_handoff.HandoffContractError as exc:\n    if \"has kind\" in exc.message:\n        # wrong artifact in place: delete it and regenerate with the correct leg\n        ...","preventionTips":["Never rename one handoff artifact to another's filename.","Let each leg write its own file; the file names (discover-nominations.json / discover-pending.json) are fixed."],"tags":["discovery","handoff","schema","protocol-state","exit-code-2"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}