Hmbown/CodeWhale · error · ValidationError
publish package list is missing workspace crates
Error message
publish package list is missing workspace crates: {missing} / publish package list contains non-workspace crates: {extra} What it means
The validator compares the crates listed in scripts/release/crates.sh (ordered_crates, the publish order) against the codewhale-* crates found in cargo metadata. If the two sets differ in either direction — a workspace release crate missing from the publish list, or a listed crate that is not in the workspace — it raises a combined error listing the missing and extra names.
Solutions
- Read the `missing`/`extra` names in the error message.
- Add each missing workspace crate to scripts/release/crates.sh in correct dependency order.
- Remove or correct each extra entry that is not a workspace crate.
- Re-run the validator; if order errors appear next, fix positions before re-checking.
Example fix
// before (scripts/release/crates.sh) CRATES=(codewhale-config codewhale-protocol) // after CRATES=(codewhale-config codewhale-protocol codewhale-tui)
Defensive patterns
Strategy: validation
Validate before calling
import subprocess, json
meta = json.loads(subprocess.check_output(['cargo','metadata','--format-version','1']))
ws = {p['name'] for p in meta['packages'] if p['name'].startswith('codewhale-')}
listed = set(read_crates_sh())
print('missing:', ws - listed, 'extra:', listed - ws) Try / catch
try:
validate_order(...)
except ValidationError as e:
for line in str(e).splitlines(): print('fix inventory:', line) Prevention
- Add the crates.sh update to the checklist for every new codewhale-* crate
- Generate crates.sh from cargo metadata instead of maintaining it by hand
- Rename crates and crates.sh entries in the same commit
When it happens
Trigger: Adding a new codewhale-* crate to the workspace without appending it to crates.sh; renaming or removing a crate without updating crates.sh; listing a crate in crates.sh that no longer exists or is not named codewhale-*.
Common situations: Release-day checklist misses the new crate; a crate is renamed (e.g. codewhale-core → codewhale-protocol) and crates.sh keeps the old name; crates.sh contains a typo.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- depends on workspace crate [ ], which is not in the…
- Cargo metadata contains duplicate workspace package names
- cargo metadata failed with exit code
- could not read Cargo metadata
- Move every workspace dependency before its dependent in…
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/b6385abb87003a24.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/release/validate-crate-publish-order.py:118
rendered = ", ".join(str(version) for version in versions)
raise ValidationError(f"workspace packages have mixed versions: {rendered}")
workspace_by_name = {package["name"]: package for package in packages}
release_names = sorted(
name for name in workspace_by_name if name.startswith("codewhale-")
)
ordered_set = set(ordered_crates)
missing = sorted(set(release_names) - ordered_set)
extra = sorted(ordered_set - set(release_names))
if missing or extra:
messages = []
if missing:
messages.append("publish package list is missing workspace crates: " + " ".join(missing))
if extra:
messages.append(
"publish package list contains non-workspace crates: " + " ".join(extra)
)
raise ValidationError("\n".join(messages))
positions = {name: index for index, name in enumerate(ordered_crates)}
has_workspace_dependencies = {name: False for name in release_names}
publish_edges: set[tuple[str, str, str]] = set()
for dependent in release_names:
dependencies = workspace_by_name[dependent].get("dependencies", [])
if not isinstance(dependencies, list):
raise ValidationError(f"Cargo metadata dependencies for {dependent} must be a list")
for dependency in dependencies:
if not isinstance(dependency, dict) or dependency.get("path") is None:
continue
dependency_name = dependency.get("name")
if dependency_name not in workspace_by_name:
continue
has_workspace_dependencies[dependent] = True
kind = dependency.get("kind") or "normal"
# Cargo does not compile dev-dependencies while verifying a publish.
# They may legitimately point back across the publication DAG.View on GitHub (pinned to 433685b202)