abhigyanpatwari/GitNexus · error · Error
version is required in group.yaml
Error message
version is required in group.yaml
What it means
Thrown by parseGroupConfig() when the parsed group.yaml object has no `version` key. The schema requires an explicit version: 1 at the top level so future format changes can be detected and migrated; there is no default. It is the first field check after the object-shape check.
Solutions
- Add `version: 1` as the first key of group.yaml.
- Copy the canonical minimal template (version/name/repos) from the gitnexus group docs and extend it.
- Run a quick YAML sanity check before group sync if you generate the file programmatically.
Example fix
# before (group.yaml) name: my-group repos: services/api: https://github.com/org/api # -> Error: version is required in group.yaml # after version: 1 name: my-group repos: services/api: https://github.com/org/api
Defensive patterns
Strategy: validation
Validate before calling
import yaml from 'js-yaml';
export function requireGroupVersion(content: string): void {
const doc = yaml.load(content, { schema: yaml.JSON_SCHEMA }) as Record<string, unknown>;
if (!('version' in doc)) {
throw new Error('group.yaml: add `version: 1` as the first key');
}
} Type guard
import yaml from 'js-yaml';
export const hasVersionKey = (content: string): boolean => {
try {
const doc = yaml.load(content, { schema: yaml.JSON_SCHEMA }) as Record<string, unknown>;
return doc != null && typeof doc === 'object' && 'version' in doc;
} catch {
return false;
}
}; Try / catch
try {
config = await loadGroupConfig(groupDir);
} catch (err) {
if (err instanceof Error && err.message === 'version is required in group.yaml') {
throw new Error('group.yaml is missing its schema header — add `version: 1` at the top', { cause: err });
}
throw err;
} Prevention
- Start every group.yaml from the canonical header: version, then name, then repos.
- Add a schema linter (or json-schema validation) for group.yaml to CI.
- When authoring manifests programmatically, emit version: 1 first so it is never forgotten.
When it happens
Trigger: Loading a group.yaml that simply omits the version key — typically hand-written files that start with name/repos, or templates copied from an example that left version out.
Common situations: Writing a first group.yaml from memory and forgetting the header; an example in a blog post omitting version; converting from another tool's manifest format that has no version concept.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- links[ ].contract is required
- name is required in group.yaml
- repos is required in group.yaml (must be a mapping)
- Invalid YAML: expected an object
- links[ ].from " " does not match any repo path in group
AI-assisted analysis of abhigyanpatwari/GitNexus@52924ef12c (2026-08-20).
Data as JSON: /api/errors/37b8e40f945b7266.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/core/group/config-parser.ts:54
thrift: true,
topics: true,
includes: false,
workspace_deps: false,
};
const DEFAULT_MATCHING = {
exclude_links_paths: [] as string[],
exclude_links_param_only_paths: false,
};
export function parseGroupConfig(yamlContent: string): GroupConfig {
const raw = yaml.load(yamlContent, { schema: yaml.JSON_SCHEMA }) as Record<string, unknown>;
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
throw new Error('Invalid YAML: expected an object');
}
if (raw.version === undefined) throw new Error('version is required in group.yaml');
if (raw.version !== 1) {
throw new Error(`Unsupported group.yaml version: ${raw.version}. Expected 1.`);
}
if (!raw.name || typeof raw.name !== 'string') throw new Error('name is required in group.yaml');
if (!raw.repos || typeof raw.repos !== 'object' || Array.isArray(raw.repos)) {
throw new Error('repos is required in group.yaml (must be a mapping)');
}
const reposRaw = raw.repos as Record<string, unknown>;
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();
}View on GitHub (pinned to 52924ef12c)