github/spec-kit · error · BundlerError

Bundle '{manifest.bundle.id}' targets integration '{required

Error message

Bundle '{manifest.bundle.id}' targets integration '{required}', but this project's active integration is '{active_integration}'. Installing it would conflict; aborting with no changes.

What it means

FR-019 integration-clash guard in resolve_install_plan(): the bundle pins an integration (manifest.integration.id) that differs from the project's active integration (from .specify/integration.json, stripped like clean_integration_key). Installing would silently switch agents, so resolution aborts with no changes. Note the active value is normalized first: blank strings become None, padded values are stripped.

Source

Thrown at src/specify_cli/bundler/services/resolver.py:94

            )

    # FR-019: integration-compatibility — a bundle that pins a different
    # integration than the project's active one halts (no silent change).
    #
    # A blank integration arrives as ``""``, not ``None`` — which is not a usable
    # integration id but satisfied NEITHER guard below (the first is a truthiness
    # test, the second an ``is None`` test), so a pinned bundle was silently
    # adopted: precisely the outcome this guard exists to prevent. Treat blank as
    # indeterminate, and strip first like the writer
    # (``integration_state.clean_integration_key``) so a padded value is not
    # reported as clashing with itself.
    if active_integration is not None:
        active_integration = active_integration.strip() or None
    effective_integration = active_integration
    if manifest.integration is not None:
        required = manifest.integration.id
        if active_integration and required != active_integration:
            raise BundlerError(
                f"Bundle '{manifest.bundle.id}' targets integration '{required}', "
                f"but this project's active integration is '{active_integration}'. "
                "Installing it would conflict; aborting with no changes."
            )
        if active_integration is None and not integration_explicit:
            raise BundlerError(
                f"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."
            )
        effective_integration = required

    warnings: list[str] = []
    if manifest.requires.tools:
        warnings.append(
            "Requires external tools: " + ", ".join(manifest.requires.tools)

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Install with an explicit override matching the bundle's target only if intentional: re-initialize or pass the pinned integration (specify bundle install <id> --integration <id> is only accepted when it matches; otherwise switch the project).
  2. Switch the project's active integration to the bundle's target (re-run specify init --integration <id>) if you want that bundle.
  3. Use a variant of the bundle without an integration pin (manifest.integration: null) or one targeting your active integration.
  4. If you author the bundle, remove the integration pin when the content is agent-neutral.

Example fix

# before: project initialized with --integration claude,
# bundle.yml pins:
integration:
  id: cursor-agent

# after: pin to the project's integration, or drop the pin
integration:
  id: claude
# or remove the integration block entirely
Defensive patterns

Strategy: validation

Validate before calling

from specify_cli.bundler.services.integration_state import active_integration

detected = active_integration(project_root)
if manifest.integration is not None and detected and manifest.integration.id != detected:
    print(f"Skip: bundle targets {manifest.integration.id}, project uses {detected}")

Type guard

def bundle_matches_project(manifest, active: str | None) -> bool:
    return manifest.integration is None or active is None or manifest.integration.id == active

Try / catch

try:
    resolve_install_plan(manifest, active_integration=detected, ...)
except BundlerError as exc:
    if "Installing it would conflict" in str(exc):
        # either switch project integration or pick another bundle
        ...

Prevention

When it happens

Trigger: resolve_install_plan(manifest, active_integration='claude', ...) where the bundle.yml declares integration: {id: cursor-agent}; via 'specify bundle install <bundle>' in a project initialized with a different agent than the bundle targets.

Common situations: Team shares a bundle authored for Claude Code but a teammate's project was initialized with --integration gemini; mixing bundles authored for different agents in one project.

Related errors


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/72179a5d2a464f1a. Report an issue: GitHub.