abhigyanpatwari/GitNexus · error
links[ ].to " " does not match any repo path in group
Error message
links[${i}].to "${link.to}" does not match any repo path in group What it means
Thrown while validating a group.yaml links entry: the link's `to` value is missing or does not match any key of the repos mapping. Same rule as the from-side check — every link endpoint must be a declared repo path in this manifest — but for the destination side of the contract link.
Solutions
- Set links[i].to to the exact repos key of the destination repo (compare with the echoed value in the message).
- Remove the stale link entirely if the destination repo is no longer part of the group.
- After any repos key rename, sweep all links[].from and links[].to for the old key.
Example fix
# before (group.yaml)
repos:
services/api: https://github.com/org/api
links:
- from: services/api
to: service/web # typo: key is services/web
# -> Error: links[0].to "service/web" does not match any repo path in group
# after
links:
- from: services/api
to: services/web Defensive patterns
Strategy: validation
Validate before calling
import yaml from 'js-yaml';
// Both link endpoints must be declared repos keys; catches `to` typos early.
export function validateLinkTargets(content: string): void {
const doc = yaml.load(content, { schema: yaml.JSON_SCHEMA }) as Record<string, any>;
const repoPaths = new Set(Object.keys(doc.repos ?? {}));
const dangling = (doc.links ?? [])
.map((l: any, i: number) => ({ i, to: l?.to, ok: repoPaths.has(l?.to) }))
.filter((x: any) => !x.ok);
if (dangling.length) {
throw new Error(
`dangling link targets: ${dangling.map((d: any) => `links[${d.i}].to=${JSON.stringify(d.to)}`).join('; ')}`,
);
}
} Type guard
export const isKnownRepoPath = (p: unknown, repoPaths: Set<string>): p is string => typeof p === 'string' && repoPaths.has(p);
Try / catch
try {
config = await loadGroupConfig(groupDir);
} catch (err) {
if (err instanceof Error && /links\[\d+\]\.to .* does not match any repo path/.test(err.message)) {
throw new Error(
'link destination is not a repo in this group — fix the repos key or delete the stale link',
{ cause: err },
);
}
throw err;
} Prevention
- When removing a repo from repos, delete or rewrite every link pointing at it in the same commit.
- Validate the whole links list in one pass (see validationCode) instead of fixing one error per sync attempt.
- Keep a naming convention for paths so to/from typos are visually obvious in review.
When it happens
Trigger: A links[i].to that references a repo path not present in repos: destination repo deleted from the group but the link kept, a typo, or an absolute path where the mapping uses relative keys.
Common situations: Removing a consumer repo from repos during a cleanup while its provider link stays; a link pasted from another group manifest whose paths differ; inconsistent use of nested vs flat path keys.
Related errors
- links[ ].from " " does not match any repo path in group
- links[ ].contract is required
- links[ ].role " " is invalid. Expected: provider | consumer
- links[ ].type " " is invalid. Expected
- Invalid YAML: expected an object
AI-assisted analysis of abhigyanpatwari/GitNexus@52924ef12c (2026-09-01).
Data as JSON: /api/errors/0ad7c0151b227bb9.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/core/group/config-parser.ts:82
const repos: Record<string, string> = {};
for (const [memberPath, registryName] of Object.entries(reposRaw)) {
if (typeof registryName !== 'string' || registryName.trim() === '') {
throw new Error(
`repos["${memberPath}"] must be a non-empty registry name string, not ${typeof registryName}`,
);
}
repos[memberPath] = registryName.trim();
}
const repoPaths = new Set(Object.keys(repos));
const rawLinks = (raw.links as unknown[]) || [];
const links: GroupManifestLink[] = rawLinks.map((l: unknown, i: number) => {
const link = l as Record<string, unknown>;
if (!link.from || !repoPaths.has(link.from as string)) {
throw new Error(`links[${i}].from "${link.from}" does not match any repo path in group`);
}
if (!link.to || !repoPaths.has(link.to as string)) {
throw new Error(`links[${i}].to "${link.to}" does not match any repo path in group`);
}
if (!VALID_CONTRACT_TYPES.includes(link.type as ManifestContractType)) {
throw new Error(
`links[${i}].type "${link.type}" is invalid. Expected: ${VALID_CONTRACT_TYPES.join(', ')}`,
);
}
if (!VALID_ROLES.includes(link.role as ContractRole)) {
throw new Error(`links[${i}].role "${link.role}" is invalid. Expected: provider | consumer`);
}
if (
link.contract === undefined ||
link.contract === null ||
String(link.contract).trim() === ''
) {
throw new Error(`links[${i}].contract is required`);
}
return {
from: link.from as string,View on GitHub (pinned to 52924ef12c)