{"record":{"id":"59b70d930d45bc93","repo":"abhigyanpatwari/GitNexus","slug":"group-sync-manifest-link-link-type-link-con","errorCode":null,"errorMessage":"[group/sync] manifest link ${link.type}:${link.contract} references repos not in config.repos: ${dangling.join(', ')} — cross-links will use synthetic UIDs","messagePattern":"\\[group/sync\\] manifest link (.+?):(.+?) references repos not in config\\.repos: (.+?) — cross-links will use synthetic UIDs","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"gitnexus/src/core/group/sync.ts","lineNumber":318,"sourceCode":"        if (opts?.verbose) {\n          for (const s of wsResult.stats) {\n            logger.info(\n              `  workspace-deps: discovered ${s.linkCount} cross-${s.ecosystem.toLowerCase()} links from ${s.projectCount} ${s.ecosystem} projects`,\n            );\n          }\n        }\n      }\n    }\n\n    if (allLinks.length > 0) {\n      // knownRepos = repos that actually initialized (have a pool handle), NOT\n      // every config.repos entry — a missing/failed repo has no handle, and\n      // intersecting against config keys would try to initLbug an undefined path.\n      const knownRepos = new Set(repoHandles.keys());\n      for (const link of allLinks) {\n        const dangling = [link.from, link.to].filter((r) => !knownRepos.has(r));\n        if (dangling.length > 0) {\n          logger.warn(\n            `[group/sync] manifest link ${link.type}:${link.contract} references repos not in config.repos: ${dangling.join(', ')} — cross-links will use synthetic UIDs`,\n          );\n        }\n      }\n\n      const manifestEx = new ManifestExtractor();\n      const windows = partitionManifestWindows(allLinks, knownRepos, getMaxResidentRepos());\n\n      // Resolve one window at a time: re-init + lease only the window's repos,\n      // resolve its links, then RELEASE (not close) the leases. Released repos\n      // become evictable and the pool's LRU reclaims them — bounding peak\n      // residency to ≤ getMaxResidentRepos() distinct repos per window while\n      // avoiding teardown of an entry a concurrent MCP reader may share\n      // (PR #2191 review, Findings 1 & 3).\n      for (const window of windows) {\n        const windowReleases: Array<() => void> = [];\n        try {\n          const windowExecutors = new Map<string, CypherExecutor>();","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/core/group/sync.ts#L300-L336","documentation":"During group sync, a manifest-declared link (link.type:link.contract) has from/to endpoints that are not in knownRepos — the set of repos that actually initialized and hold a pool handle, not merely everything listed in config.repos. Cross-links for those endpoints fall back to synthetic UIDs, so they cannot be traced to real indexed symbols.","triggerScenarios":"A repo referenced by a link was removed from (or never added to) config.repos, or its initialization failed (bad path, permissions) so it never gained a pool handle; the message names the exact dangling endpoints.","commonSituations":"Removing or renaming a group repo without updating the links manifest; typos in repo names in link declarations; a repo whose path fails to init during sync (clone missing, permissions).","solutions":["Add the missing repo(s) named in the message to the group's config.repos with correct paths","Fix why the repo failed to initialize (path, missing clone, permissions) so it gains a pool handle","Remove or update stale link entries referencing repos no longer in the group","Re-run group sync and confirm cross-links use real symbol UIDs"],"exampleFix":"# before — group config\nrepos = [\"api\", \"web\"]\n# links manifest references \"mobile\" (not configured)\n\n# after — add the repo or drop the link\nrepos = [\"api\", \"web\", \"mobile\"]","handlingStrategy":"validation","validationCode":"// Validate before sync: every link endpoint must be a configured repo\nconst configured = new Set(groupConfig.repos); // config.repos entries\nconst dangling = allLinks.flatMap((link) =>\n  [link.from, link.to].filter((repo) => !configured.has(repo)),\n);\nif (dangling.length > 0) {\n  throw new Error(\n    `links reference unconfigured repos: ${[...new Set(dangling)].join(', ')} — ` +\n    `add them to config.repos or remove the links`,\n  );\n}","typeGuard":"function linkEndpointsConfigured(link: { from: string; to: string }, configured: ReadonlySet<string>): boolean {\n  return configured.has(link.from) && configured.has(link.to);\n}","tryCatchPattern":null,"preventionTips":["Keep the links manifest in lockstep with config.repos — update links whenever a repo is added, removed, or renamed","Validate repo paths and permissions before sync so every configured repo actually initializes and gains a pool handle","Add a pre-sync lint that fails on any link endpoint not present in config.repos"],"tags":["group","sync","cross-links","config","dangling-reference"],"backgroundTag":"dangling-config-reference","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}