{"record":{"id":"f5b458fedc02b502","repo":"abhigyanpatwari/GitNexus","slug":"repos-is-required-in-group-yaml-must-be-a-mapping","errorCode":null,"errorMessage":"repos is required in group.yaml (must be a mapping)","messagePattern":"repos is required in group\\.yaml \\(must be a mapping\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/group/config-parser.ts","lineNumber":59,"sourceCode":"  max_candidates_per_step: 3,\n  exclude_links_paths: [] as string[],\n  exclude_links_param_only_paths: false,\n};\n\nexport function parseGroupConfig(yamlContent: string): GroupConfig {\n  const raw = yaml.load(yamlContent, { schema: yaml.JSON_SCHEMA }) as Record<string, unknown>;\n\n  if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n    throw new Error('Invalid YAML: expected an object');\n  }\n\n  if (raw.version === undefined) throw new Error('version is required in group.yaml');\n  if (raw.version !== 1) {\n    throw new Error(`Unsupported group.yaml version: ${raw.version}. Expected 1.`);\n  }\n  if (!raw.name || typeof raw.name !== 'string') throw new Error('name is required in group.yaml');\n  if (!raw.repos || typeof raw.repos !== 'object' || Array.isArray(raw.repos)) {\n    throw new Error('repos is required in group.yaml (must be a mapping)');\n  }\n\n  const repos = raw.repos as Record<string, string>;\n  const repoPaths = new Set(Object.keys(repos));\n\n  const rawLinks = (raw.links as unknown[]) || [];\n  const links: GroupManifestLink[] = rawLinks.map((l: unknown, i: number) => {\n    const link = l as Record<string, unknown>;\n    if (!link.from || !repoPaths.has(link.from as string)) {\n      throw new Error(`links[${i}].from \"${link.from}\" does not match any repo path in group`);\n    }\n    if (!link.to || !repoPaths.has(link.to as string)) {\n      throw new Error(`links[${i}].to \"${link.to}\" does not match any repo path in group`);\n    }\n    if (!VALID_CONTRACT_TYPES.includes(link.type as ContractType)) {\n      throw new Error(\n        `links[${i}].type \"${link.type}\" is invalid. Expected: ${VALID_CONTRACT_TYPES.join(', ')}`,\n      );","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/gitnexus/src/core/group/config-parser.ts#L41-L77","documentation":"Thrown by parseGroupConfig when the 'repos' field is missing, null, not an object, or an array. repos must be a YAML mapping of repo-path strings (the keys become the valid set of endpoints for link.from/link.to). This check runs before links are validated so that the repoPaths set is well-defined.","triggerScenarios":"group.yaml with no 'repos' key; repos set to a YAML array; repos set to a scalar; repos present but null.","commonSituations":"A manifest that lists repos as an array (e.g. `repos: [./a, ./b]`) instead of a mapping (e.g. `repos: { './a': ./a }`); a template where repos was emptied and the braces removed; misreading the schema docs.","solutions":["Make 'repos' a YAML mapping. The keys are the repo paths used in links; values are the local checkout paths.","If you have no repos yet, write `repos: {}` (empty mapping) rather than omitting the key or using an array."],"exampleFix":"# before — array, rejected\nrepos:\n  - ./services/api\n  - ./services/worker\n\n# after — mapping\nrepos:\n  ./services/api: ./services/api\n  ./services/worker: ./services/worker","handlingStrategy":"validation","validationCode":"const raw = yaml.load(text, { schema: yaml.JSON_SCHEMA }) as Record<string, unknown>;\nif (raw.repos === null || typeof raw.repos !== 'object' || Array.isArray(raw.repos)) {\n  throw new Error('group.yaml requires repos as a mapping of path -> checkout path');\n}","typeGuard":"function isReposMapping(v: unknown): v is Record<string, string> {\n  return v !== null && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":null,"preventionTips":["Use a YAML mapping for repos, not an array — `repos: { './a': './a' }`.","When empty, write `repos: {}` explicitly.","Document the mapping-vs-list distinction in any group authoring guide."],"tags":["yaml","group-config","validation","repos","config-parser"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}