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

  1. Set links[i].to to the exact repos key of the destination repo (compare with the echoed value in the message).
  2. Remove the stale link entirely if the destination repo is no longer part of the group.
  3. 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 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


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)