{"record":{"id":"afcfd1dc903de95e","repo":"github/spec-kit","slug":"bundle-manifest-bundle-id-targets-integration-afcfd1","errorCode":null,"errorMessage":"Bundle '{manifest.bundle.id}' targets integration '{required}', but this project's active integration could not be determined (missing or unreadable .specify/integration.json). Re-run with '--integration' to confirm the target, or repair the project before installing.","messagePattern":"Bundle '(.+?)' targets integration '(.+?)', but this project's active integration could not be determined \\(missing or unreadable \\.specify/integration\\.json\\)\\. Re-run with '--integration' to confirm the target, or repair the project before installing\\.","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/bundler/services/resolver.py","lineNumber":100,"sourceCode":"    # integration id but satisfied NEITHER guard below (the first is a truthiness\n    # test, the second an ``is None`` test), so a pinned bundle was silently\n    # adopted: precisely the outcome this guard exists to prevent. Treat blank as\n    # indeterminate, and strip first like the writer\n    # (``integration_state.clean_integration_key``) so a padded value is not\n    # reported as clashing with itself.\n    if active_integration is not None:\n        active_integration = active_integration.strip() or None\n    effective_integration = active_integration\n    if manifest.integration is not None:\n        required = manifest.integration.id\n        if active_integration and required != active_integration:\n            raise BundlerError(\n                f\"Bundle '{manifest.bundle.id}' targets integration '{required}', \"\n                f\"but this project's active integration is '{active_integration}'. \"\n                \"Installing it would conflict; aborting with no changes.\"\n            )\n        if active_integration is None and not integration_explicit:\n            raise BundlerError(\n                f\"Bundle '{manifest.bundle.id}' targets integration '{required}', \"\n                \"but this project's active integration could not be determined \"\n                \"(missing or unreadable .specify/integration.json). Re-run with \"\n                \"'--integration' to confirm the target, or repair the project \"\n                \"before installing.\"\n            )\n        effective_integration = required\n\n    warnings: list[str] = []\n    if manifest.requires.tools:\n        warnings.append(\n            \"Requires external tools: \" + \", \".join(manifest.requires.tools)\n        )\n    if manifest.requires.mcp:\n        warnings.append(\"Requires MCP servers: \" + \", \".join(manifest.requires.mcp))\n\n    return InstallPlan(\n        bundle_id=manifest.bundle.id,","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/bundler/services/resolver.py#L82-L118","documentation":"The second FR-019 branch: the bundle pins an integration but the project's active integration is None — .specify/integration.json is missing or unreadable — and the caller did not pass an explicit --integration (integration_explicit is False). Rather than silently adopting the bundle's required integration, resolution fails and asks for an explicit confirmation.","triggerScenarios":"resolve_install_plan(manifest, active_integration=None, integration_explicit=False) when manifest.integration is not None; via 'specify bundle install <pinned-bundle>' in a directory where .specify/integration.json was deleted, corrupted, or never created.","commonSituations":"Installing into a manually-created .specify directory instead of one produced by specify init; a partially-deleted project; CI runs that strip state files; .specify/integration.json containing an unreadable/invalid payload.","solutions":["Re-run with an explicit target: specify bundle install <id> --integration <integration-id>.","Repair the project state: re-run specify init (or recreate .specify/integration.json) so active_integration is detectable, then retry without the flag.","If the integration.json exists but is corrupt JSON, fix or delete-and-reinit so detection works."],"exampleFix":"# before\nspecify bundle install my-bundle\n\n# after\nspecify bundle install my-bundle --integration claude","handlingStrategy":"validation","validationCode":"from specify_cli.bundler.services.integration_state import active_integration\n\ndetected = active_integration(project_root)\nif detected is None and manifest.integration is not None:\n    integration = input(\"Active integration unknown; pass --integration explicitly\") or abort","typeGuard":"def needs_explicit_integration(manifest, active: str | None) -> bool:\n    \"\"\"True when resolution will demand an explicit --integration.\"\"\"\n    return manifest.integration is not None and active is None","tryCatchPattern":"try:\n    resolve_install_plan(manifest, active_integration=detected, integration_explicit=False, ...)\nexcept BundlerError as exc:\n    if \"could not be determined\" in str(exc):\n        # retry with explicit override: specify bundle install <id> --integration claude\n        ...","preventionTips":["Always initialize projects with specify init so .specify/integration.json exists.","Pass --integration explicitly in scripts/CI when installing pinned bundles.","Do not hand-delete files under .specify."],"tags":["bundler","integration","project-state","guard"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}