Skip to content

fix(extensions): skip catalog entries without a version on update - #5108

Open
MannXo wants to merge 3 commits into
github:mainfrom
MannXo:fix/5082-update-missing-version
Open

MannXo wants to merge 3 commits into
github:mainfrom
MannXo:fix/5082-update-missing-version

Conversation

@MannXo

@MannXo MannXo commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Description

discover_updates read the catalog version with ext_info["version"], so a catalog entry without version made specify extension update exit 1 with KeyError: 'version', and the installed extensions after it were never checked. A null or list value crashed the same way, with TypeError and AttributeError.

This PR accepts the catalog version only when it is a string. Anything else is skipped with a warning and the loop carries on. A missing version is reported as Missing catalog version, and any other type (null, a list, or a number such as 2) as Invalid catalog version: expected a string, got <type>, in the style of ExtensionManifest validation. An unparseable string keeps the existing Invalid catalog version '<value>' warning. Entries with a valid version behave as before. A number is rejected rather than converted: the download step passes the catalog's raw value to build_safe_download_path, which accepts only a string (_download_security.py:442), so a numeric version would be offered as an update that then fails to download.

The issue's repro script, on main (67e0f72), last traceback line only:

exit code: 1
🔄 Checking for updates...

Warning: Using non-default extension catalog. Only use catalogs from sources you trust.

KeyError: 'version'

With this PR:

exit code: 0
🔄 Checking for updates...

⚠  aaa: Missing catalog version (skipping)
✓ bbb: Up to date (v1.0.0)

All extensions are up to date!
Warning: Using non-default extension catalog. Only use catalogs from sources you trust.

The same script with "version": 2 on aaa:

⚠  aaa: Invalid catalog version: expected a string, got int (skipping)
✓ bbb: Up to date (v1.0.0)

Fixes #5082

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest
  • Tested with a sample project (if applicable)

New tests:

  • test_discovery_skips_catalog_entry_without_valid_version in tests/specify_cli/extensions/test_command_update_discovery.py, for a missing, null, list, numeric and unparseable version. The broken entry comes first, and the test checks the exact skip warning for each case and that the second extension's update is still found.
  • test_update_skips_catalog_entry_without_version in tests/specify_cli/extensions/test_command_update.py runs specify extension update through the CLI and checks exit code 0, the Missing catalog version warning, and an unchanged registry.

With only src/ reverted to main, the 5 missing and wrong-type cases fail (KeyError, TypeError, AttributeError, exit code 1). With the fix, the 32 tests in those two files pass.

Full suite on macOS, Python 3.14.6, pytest -n 2 as in CI: 12808 passed, 434 skipped, none failed.

uvx ruff@0.15.0 check src tests passes, and so does git diff --check.

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (fill in the disclosure below)

AI disclosure: Claude Code (model: claude-opus-5-5, autonomous) reproduced the bug, wrote the fix and tests, ran the suite and lint, and drafted this description.

`specify extension update` read the catalog version with
`ext_info["version"]`, so an entry with no `version` raised KeyError,
and a null or list value raised TypeError or AttributeError. Any of
these aborted the command before the remaining installed extensions
were checked. Read the value the way `specify workflow update` does, so
these entries take the existing "Invalid catalog version ... (skipping)"
path.

Fixes github#5082
@MannXo
MannXo requested a review from mnriem as a code owner October 24, 2026 17:35
@mnriem mnriem added the triage-must-have Verdict: high-value, important work for Spec Kit — do first label Oct 25, 2026
@mnriem
mnriem requested a max review from Copilot October 26, 2026 13:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Numeric catalog versions now pass discovery but are rejected during download, offering updates that cannot complete.

1 open issue
What changed in this PR

Addresses #5082 by preventing missing or malformed catalog version fields from aborting Specify CLI extension update checks.

Changes:

  • Reads catalog versions defensively and reuses the existing skip warning.
  • Adds discovery and CLI regression coverage for malformed entries, continued checking, and unchanged installed state.

The PR’s reported before-and-after results were reviewed; project tests were not rerun here.

File Description
tests/​specify_cli/​extensions/​test_command_update.py Checks successful CLI completion, the skip warning, and unchanged registry state.
tests/​specify_cli/​extensions/​test_command_update_discovery.py Covers missing, null, and list versions while verifying discovery continues.
src/​specify_cli/​extensions/​_command_update_discovery.py Converts optional catalog version values to strings before parsing.

Review effort: Max

Comment thread src/specify_cli/extensions/_command_update_discovery.py Outdated
@mnriem

mnriem commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

@mnriem mnriem added the author-awaiting Waiting on author response label Oct 26, 2026
…date

A numeric catalog version such as `"version": 2` passed discovery once
coerced with str(), but the download rejects non-string versions, so the
update was offered and then always failed. Require a string and take the
existing "Invalid catalog version ... (skipping)" path otherwise.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The narrowly scoped fix has targeted regression coverage and no unresolved blocking issues.

1 open issue
1 resolved since last review

Review effort: Max

Comment on lines +102 to +103
if not isinstance(raw_catalog_version, str):
raise pkg_version.InvalidVersion(raw_catalog_version)
@mnriem

mnriem commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

@MannXo

MannXo commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

Addressed in 7cef29a. Discovery now accepts a catalog version only when it is a string, so a number such as 2 takes the existing skip path instead of being offered as an update that the download then rejects. {"version": 2} is added to the parametrized discovery test, and the description is updated to say versions are string-only.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues are identified for the change to skip malformed catalog versions during extension update checks.

1 open issue

Review effort: Max

@mnriem

mnriem commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

@MannXo

MannXo commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

The open Copilot thread at _command_update_discovery.py:103 is about the PR description, not the code, and the description already says versions are string-only (second paragraph) and lists the numeric case under Testing. Copilot's latest review on 7cef29a raised nothing new, so that thread only needs resolving, which I've left to you.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

An active finding notes that non-string catalog versions produce a misleading warning rather than explicitly identifying the expected and received types.

2 open issues

Review effort: Max

Comment on lines +102 to +103
if not isinstance(raw_catalog_version, str):
raise pkg_version.InvalidVersion(raw_catalog_version)
@mnriem

mnriem commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback. If not applicable, please explain why

A catalog entry with "version": 2 was reported as "Invalid catalog
version '2'", which reads as a rejected version string. Report a missing
version and a non-string one separately, naming the received type as
ExtensionManifest validation does.
@MannXo

MannXo commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

Addressed in bfb786b. A missing catalog version now warns Missing catalog version, and a non-string one says expected a string, got int (or whichever type it received), with the exact warnings asserted in both test files. The description is updated to match, and it also covers the older :103 thread about the description.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author-awaiting Waiting on author response triage-must-have Verdict: high-value, important work for Spec Kit — do first

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: specify extension update crashes with KeyError when a catalog entry has no version, and stops checking the other extensions

3 participants