docs(backstage-plugins): fix install guide inaccuracies found in end-to-end test - #818
Conversation
|
Warning Review limit reached
Next review available in: 31 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe Backstage plugin documentation now covers updated compatibility versions, stable installation prerequisites, Yarn and GitHub Packages configuration, catalog permission behavior, workflow feature flags, and troubleshooting steps. ChangesBackstage plugin documentation
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@docs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx`:
- Around line 24-32: Update all OpenChoreo install and upgrade commands in this
guide, including the migration guide, to constrain package versions to the
tested 1.2.x minor by replacing caret ranges such as ^1.2.0 with ~1.2.0 or
1.2.x. Preserve the separate `@next` prerelease command.
- Around line 637-639: Update the catalog rules guidance in catalog-sync.mdx,
installing-into-existing-backstage.mdx, and troubleshooting.mdx so
catalog.rules.allow is not required for EntityProvider entities submitted
through EntityProviderConnection.applyMutation. Retain the requirement only for
static catalog.locations, and keep the installation and troubleshooting
explanations consistent across all three files.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: f91520ff-89b9-4eb6-a1b5-29855deed287
⛔ Files ignored due to path filters (3)
versioned_docs/version-v1.2.x/platform-engineer-guide/backstage-plugins/compatibility-matrix.mdxis excluded by!versioned_docs/**versioned_docs/version-v1.2.x/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdxis excluded by!versioned_docs/**versioned_docs/version-v1.2.x/platform-engineer-guide/backstage-plugins/troubleshooting.mdxis excluded by!versioned_docs/**
📒 Files selected for processing (3)
docs/platform-engineer-guide/backstage-plugins/compatibility-matrix.mdxdocs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdxdocs/platform-engineer-guide/backstage-plugins/troubleshooting.mdx
| :::tip Tracking prereleases | ||
|
|
||
| The install commands on this page reference `@openchoreo/<pkg>@^1.2.0`, which will be the GA dist-tag of the next plugin release. While `1.2.0` is still under active development, install via the `next` dist-tag to get the latest prerelease today: | ||
| The install commands on this page reference `@openchoreo/<pkg>@^1.2.0`, which resolves to the newest stable `1.2.x` release. Stable releases are published under the `latest` dist-tag; prereleases go to `next`. To track the cutting edge instead: | ||
|
|
||
| ```bash | ||
| yarn workspace app add @openchoreo/backstage-plugin@next | ||
| ``` | ||
|
|
||
| Once `1.2.0` GA is announced, swap `@next` for `@^1.2.0` to pin to the stable release. | ||
|
|
||
| ::: |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find every documented package range that can escape the tested 1.2.x line.
rg -n '`@openchoreo/`[^[:space:]`]+@\^1\.2\.0' docsRepository: openchoreo/openchoreo.github.io
Length of output: 6626
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- installation page: compatibility and range guidance ---'
rg -n -C 5 'compatib|1\.2\.x|1\.2\.0|\^1\.2\.0|~1\.2\.0|latest|next|stable|prerelease' \
docs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx
echo '--- migration page: compatibility and range guidance ---'
rg -n -C 4 'compatib|1\.2\.x|1\.2\.0|\^1\.2\.0|~1\.2\.0|latest|next|stable|prerelease' \
docs/platform-engineer-guide/backstage-plugins/migration-1.1-to-1.2.mdx
echo '--- repository version policy references ---'
rg -n -i -C 3 'compatibility matrix|supported versions|version matrix|semver|dist-tag|backstage-plugin' \
docs README.md .github 2>/dev/null | head -n 300
echo '--- standalone semver boundary check ---'
python3 - <<'PY'
from functools import total_ordering
`@total_ordering`
class V:
def __init__(self, s):
self.t = tuple(map(int, s.split('.')))
def __lt__(self, other): return self.t < other.t
def __eq__(self, other): return self.t == other.t
def __repr__(self): return '.'.join(map(str, self.t))
lower = V("1.2.0")
upper = V("2.0.0")
for raw in ("1.2.0", "1.2.9", "1.3.0", "1.9.9", "2.0.0"):
v = V(raw)
print(raw, "satisfies ^1.2.0:", lower <= v < upper,
"satisfies ~1.2.0:", V("1.2.0") <= v < V("1.3.0"))
PYRepository: openchoreo/openchoreo.github.io
Length of output: 50389
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- compatibility matrix ---'
matrix=$(fd -i -t f 'compatibility-matrix' docs | head -n 1)
printf 'file: %s\n' "$matrix"
wc -l "$matrix"
cat -n "$matrix"
echo '--- exact affected command blocks ---'
sed -n '160,198p' docs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx
sed -n '700,715p' docs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx
sed -n '760,775p' docs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx
sed -n '816,831p' docs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx
sed -n '12,80p' docs/platform-engineer-guide/backstage-plugins/migration-1.1-to-1.2.mdx
echo '--- semver boundary probe ---'
python3 - <<'PY'
def v(s):
return tuple(int(x) for x in s.split("."))
tests = ("1.2.0", "1.2.9", "1.3.0", "1.9.9", "2.0.0")
for item in tests:
x = v(item)
caret = v("1.2.0") <= x < v("2.0.0")
tilde = v("1.2.0") <= x < v("1.3.0")
print(f"{item}: ^1.2.0={caret}, ~1.2.0={tilde}")
PYRepository: openchoreo/openchoreo.github.io
Length of output: 16683
Restrict OpenChoreo package ranges to the tested minor.
The compatibility matrix supports only plugin set 1.2.x, but ^1.2.0 accepts 1.3.0 through <2.0.0. Use ~1.2.0 or 1.2.x in all OpenChoreo install and upgrade commands, including the migration guide.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@docs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx`
around lines 24 - 32, Update all OpenChoreo install and upgrade commands in this
guide, including the migration guide, to constrain package versions to the
tested 1.2.x minor by replacing caret ranges such as ^1.2.0 with ~1.2.0 or
1.2.x. Preserve the separate `@next` prerelease command.
| # Only needed for static `catalog.locations` you add yourself. Entities emitted by | ||
| # an EntityProvider — which is how the OpenChoreo sync works — bypass catalog.rules | ||
| # entirely, so this block does not gate the OpenChoreo entities. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
For Backstage v1.51.0, do entities submitted through EntityProviderConnection.applyMutationpass throughcatalog.rules? Cite the Backstage v1.51.0 source code or official documentation.
💡 Result:
In Backstage v1.51.0, entities submitted through EntityProviderConnection.applyMutation are not subject to catalog.rules validation [1][2][3]. Catalog rules are primarily designed to control the ingestion of entities originating from locations (such as those defined in catalog.locations) [1][4][2]. They are enforced by the DefaultCatalogProcessingOrchestrator within the processing pipeline [3], specifically applying to entities that have an associated location spec [1][3]. Entities submitted directly via an EntityProvider through applyMutation bypass this location-based rule enforcement [1]. As outlined in the official Backstage documentation, EntityProviders provide entities directly to the catalog engine [5][6]. While these entities undergo standard catalog processing steps (such as validation by EntityPolicies and processors), they do not trigger the catalog.rules check that applies to file-based or URL-based location ingestion [1][4][3].
Citations:
- 1: support entity kind filter / allow list at entity providers ingesting Location entities backstage/backstage#12880
- 2: catalog-backend: initial catalog ingestion rules implementation backstage/backstage#2118
- 3: https://github.com/backstage/backstage/blob/1e8899a6/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts
- 4: https://github.com/backstage/backstage/blob/master/docs/features/software-catalog/configuration.md
- 5: https://backstage.io/docs/features/software-catalog/external-integrations/
- 6: https://backstage.io/api/stable/interfaces/_backstage_plugin-catalog-node.index.EntityProvider.html
🏁 Script executed:
#!/bin/bash
set -eu
for f in \
docs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx \
docs/platform-engineer-guide/backstage-plugins/troubleshooting.mdx \
docs/platform-engineer-guide/backstage-plugins/catalog-sync.mdx
do
echo "=== $f ==="
wc -l "$f"
case "$f" in
*installing-into-existing-backstage.mdx) sed -n '620,650p' "$f" ;;
*troubleshooting.mdx) sed -n '265,295p' "$f" ;;
*catalog-sync.mdx) sed -n '25,55p' "$f" ;;
esac
done
echo "=== references to catalog.rules and EntityProvider ==="
rg -n -C 3 'catalog\.rules|EntityProvider|applyMutation' docs/platform-engineer-guide/backstage-pluginsRepository: openchoreo/openchoreo.github.io
Length of output: 8990
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
import json
import urllib.request
base = "https://raw.githubusercontent.com/backstage/backstage/v1.51.0/"
paths = [
"plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts",
"plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts",
"plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts",
]
for path in paths:
url = base + path
print(f"=== {url} ===")
try:
with urllib.request.urlopen(url, timeout=20) as response:
text = response.read().decode()
except Exception as exc:
print(f"FETCH_ERROR: {exc}")
continue
lines = text.splitlines()
for i, line in enumerate(lines, 1):
if any(term in line for term in ("rules", "applyMutation", "location")):
lo, hi = max(1, i - 5), min(len(lines), i + 8)
print("\n".join(f"{n}: {lines[n-1]}" for n in range(lo, hi + 1)))
print("---")
PYRepository: openchoreo/openchoreo.github.io
Length of output: 1037
🏁 Script executed:
#!/bin/bash
set -eu
base='https://raw.githubusercontent.com/backstage/backstage/v1.51.0'
for path in \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts \
plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts
do
url="$base/$path"
echo "=== $url ==="
body="$(curl -ksSfL "$url" || true)"
if [ -z "$body" ]; then
echo "FETCH_ERROR_OR_EMPTY"
continue
fi
printf '%s\n' "$body" | nl -ba | grep -E -C 8 'catalog\.rules|rules|applyMutation|EntityProvider|location' || true
doneRepository: openchoreo/openchoreo.github.io
Length of output: 889
🏁 Script executed:
#!/bin/bash
set -eu
base='https://raw.githubusercontent.com/backstage/backstage/v1.51.0'
for path in \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts \
plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts
do
url="$base/$path"
echo "=== $url ==="
curl -ksSfL "$url" | grep -E -C 8 'catalog\.rules|rules|applyMutation|EntityProvider|location' || true
doneRepository: openchoreo/openchoreo.github.io
Length of output: 8904
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
import json, ssl, urllib.request
ctx = ssl._create_unverified_context()
url = 'https://api.github.com/repos/backstage/backstage/git/trees/v1.51.0?recursive=1'
req = urllib.request.Request(url, headers={'User-Agent': 'review-inspection'})
with urllib.request.urlopen(req, context=ctx, timeout=30) as response:
tree = json.load(response)['tree']
for item in tree:
path = item.get('path', '')
if 'catalog-backend' in path and (
'EntityProvider' in path or 'entityProvider' in path or
'EntitiesCatalog' in path or 'CatalogService' in path or
'rules' in path.lower()
):
print(path)
PYRepository: openchoreo/openchoreo.github.io
Length of output: 965
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
import ssl, urllib.request
ctx = ssl._create_unverified_context()
base = 'https://raw.githubusercontent.com/backstage/backstage/v1.51.0/'
paths = [
'plugins/catalog-backend/src/service/DefaultCatalogService.ts',
'plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts',
'plugins/catalog-backend/src/providers/EntityProviderConnection.ts',
'plugins/catalog-backend/src/providers/EntityProviderManager.ts',
]
for path in paths:
url = base + path
print(f'=== {url} ===')
try:
req = urllib.request.Request(url, headers={'User-Agent': 'review-inspection'})
with urllib.request.urlopen(req, context=ctx, timeout=20) as response:
lines = response.read().decode().splitlines()
except Exception as exc:
print(f'FETCH_ERROR: {exc}')
continue
for i, line in enumerate(lines, 1):
if any(term in line for term in ('applyMutation', 'rulesEnforcer', 'deferredEntities', 'locationKey', 'originLocation')):
lo, hi = max(1, i - 12), min(len(lines), i + 18)
print('\n'.join(f'{n}: {lines[n-1]}' for n in range(lo, hi + 1)))
print('---')
PYRepository: openchoreo/openchoreo.github.io
Length of output: 10922
🏁 Script executed:
#!/bin/bash
set -eu
tmp="$(mktemp)"
trap 'rm -f "$tmp"' EXIT
curl -ksSfL 'https://codeload.github.com/backstage/backstage/tar.gz/refs/tags/v1.51.0' -o "$tmp"
tar -tzf "$tmp" |
grep -E 'catalog-backend/.+(EntityProvider|CatalogService|ProcessingManager|Database|rules)' |
head -80Repository: openchoreo/openchoreo.github.io
Length of output: 2115
🏁 Script executed:
#!/bin/bash
set -eu
tmp="$(mktemp)"
dir="$(mktemp -d)"
trap 'rm -f "$tmp"; rm -rf "$dir"' EXIT
curl -ksSfL 'https://codeload.github.com/backstage/backstage/tar.gz/refs/tags/v1.51.0' -o "$tmp"
tar -xzf "$tmp" -C "$dir"
root="$(find "$dir" -maxdepth 1 -type d -name 'backstage-*' -print -quit)"
grep -R -n -E -C 8 'applyMutation|rulesEnforcer|deferredEntities|locationKey' \
"$root/plugins/catalog-backend" \
--include='*.ts' --include='*.tsx' | head -300Repository: openchoreo/openchoreo.github.io
Length of output: 38424
🏁 Script executed:
#!/bin/bash
set -eu
tmp="$(mktemp)"
dir="$(mktemp -d)"
trap 'rm -f "$tmp"; rm -rf "$dir"' EXIT
curl -ksSfL 'https://codeload.github.com/backstage/backstage/tar.gz/refs/tags/v1.51.0' -o "$tmp"
tar -xzf "$tmp" -C "$dir"
root="$(find "$dir" -maxdepth 1 -type d -name 'backstage-*' -print -quit)"
echo '=== applyMutation and provider connection ==='
grep -R -n -E -C 15 'applyMutation|EntityProviderConnection|connectEntityProviders' \
"$root/plugins/catalog-backend" "$root/packages/catalog-node" \
--include='*.ts' --include='*.tsx' | head -500
echo '=== relevant catalog service files ==='
find "$root/plugins/catalog-backend/src" -type f \
\( -iname '*catalog*' -o -iname '*provider*' -o -iname '*refresh*' \) \
-print | sortRepository: openchoreo/openchoreo.github.io
Length of output: 50387
Remove the catalog.rules.allow requirement for EntityProvider entities.
Backstage 1.51.0 does not apply catalog.rules to entities submitted through EntityProviderConnection.applyMutation. Update catalog-sync.mdx and its troubleshooting guidance. Keep installing-into-existing-backstage.mdx and troubleshooting.mdx consistent. Retain catalog.rules guidance only for static catalog.locations.
📍 Affects 2 files
docs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx#L637-L639(this comment)docs/platform-engineer-guide/backstage-plugins/troubleshooting.mdx#L279-L282
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@docs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx`
around lines 637 - 639, Update the catalog rules guidance in catalog-sync.mdx,
installing-into-existing-backstage.mdx, and troubleshooting.mdx so
catalog.rules.allow is not required for EntityProvider entities submitted
through EntityProviderConnection.applyMutation. Retain the requirement only for
static catalog.locations, and keep the installation and troubleshooting
explanations consistent across all three files.
What
Fixes inaccuracies in the Backstage plugins install guide found by following it end to end against a live OpenChoreo
v1.2.1cluster (auth + authz enabled) with plugin set1.2.2, from a stockcreate-appscaffold.Applied to both
docs/(next) andversioned_docs/version-v1.2.x/, sincelastVersionisv1.2.xand that is what readers get at/docs/.Fixes
1.
${GITHUB_PACKAGES_TOKEN}breaks every yarn command (§3) — the snippet used a bare variable reference. Yarn expands.yarnrc.ymlvariables on every invocation, so with the variable unset,yarn tsc,yarn startandyarn lintall abort withUsage Error: Environment variable not found (GITHUB_PACKAGES_TOKEN)before doing anything. Reproduced on Yarn 4.4.1 and 4.13.0. Now uses the:-empty-default form, plus a warning explaining why and a troubleshooting entry.2. The
.yarnrc.ymlexample was from a different scaffold than the guide targets (§3) — it showedyarnPath: .yarn/releases/yarn-4.13.0.cjsplusnpmMinimalAgeGate/npmPreapprovedPackages. Those belong to the 1.53-era scaffold. The scaffold for Backstage1.51.0, which this guide pins to, has a two-line.yarnrc.ymlwith Yarn 4.4.1 and no age gate. Following the guide literally gave a wrongyarnPathand two keys that do nothing. The example now shows only what needs adding, and the age gate moved to a note.3. Node.js version was wrong (§1, compatibility matrix) — said "20 or 22". Both the 1.51 and 1.53 scaffolds declare
"engines": { "node": "22 || 24" }, so Node 20 does not work. Now "22 or 24".4. An empty catalog was reported as complete success (§4.5, troubleshooting) — with
permission.enabled: truethe catalog is empty until OpenChoreo sign-in completes, which is correct behaviour, but nothing says so. The provider logsSuccessfully processed N entities, there is no error or warning, and the provider'sTemplateentities are not filtered, so the Scaffolder fills with OpenChoreo templates while the catalog looks empty. Added a warning at the verify step and rewrote the troubleshooting entry.5. The troubleshooting entry for that symptom named the wrong cause — "Catalog provider runs but no entities show up" advised adding kinds to
catalog.rules.allow. Entities emitted by an EntityProvider bypasscatalog.rulesentirely;catalog.rulesonly governs staticcatalog.locations. Demonstrable: the provider'sTemplateentities are admitted even whenTemplateis absent from the allow-list. Retitled to the actual symptom and corrected.6.
catalog.rulescomment in §4.4 said "The catalog must accept Domain entities from the OpenChoreo provider", which is the same misconception. Reworded.7. §7 named no config flag — sections 5 and 6 each set one; §7 had no configure step. It shares
openchoreo.features.workflows.enabledwith §6, which matters if you install §7 without §6. Added as §7.4.8. Stale prerelease callout — the intro said 1.2.0 "is still under active development" and to install via
@next. 1.2.0 shipped 2026-07-24 and^1.2.0now resolves to 1.2.2, so the tip steered new adopters onto prereleases. Rewritten as a general note about thelatest/nextdist-tags.Additions
Avoiding the downgrade (§1, §2, matrix) — the guide had you scaffold at
create-app@latestand thenversions:bump --release 1.51.0down to the tested line.@backstage/create-app@0.8.3is the release that ships Backstage1.51.0, sonpx @backstage/create-app@0.8.3lands there directly. Added as the recommended path for new apps;versions:bumpis kept for existing apps on another release line. Besides removing an install-then-downgrade cycle, it keeps@backstage/*version churn out of the first commit, so the diff that adds OpenChoreo contains only OpenChoreo changes.Optional packs need cluster-side planes (§1) — the Observability and CI/Build packs require the corresponding OpenChoreo planes, which are opt-in on the k3d quick start (
./install.sh --with-observability --with-build). Not mentioned anywhere in this guide; without them the tabs render but have no data.403 does not match expected scopes(troubleshooting) — aghCLI token is rejected bynpm.pkg.github.comregardless of its scopes; you need a classic PAT withread:packages. This is easy to hit since the guide links to token creation without saying the CLI token will not do.create-apphas no--nameflag (§1) — the bare command prompts, which breaks scripted installs. Added theprintfform.Verification
create-app@0.8.3scaffold:yarn tscexits 0, dev server starts,Successfully processed 62 entities (1 domains, 4 systems, 26 components, 3 environments, ...), zero errors in the backend log.npm run buildsucceeds with no broken-link errors;prettier --checkclean.Not addressed
openchoreo.defaultOwner: openchoreo-users(§4.4) points at a Group that nothing in the Core install creates, so every synced entity gets a dangling owner and the log showsUnable to stitch group:default/openchoreo-users. Harmless, but the fix is a product call — either wire@openchoreo/backstage-plugin-catalog-backend-module-openchoreo-usersinto Core, or have the guide pointdefaultOwnerat a group that exists. Happy to follow up whichever way maintainers prefer.