abhigyanpatwari/GitNexus · error · Error
Invalid YAML: expected an object
Error message
Invalid YAML: expected an object
What it means
Thrown by parseGroupConfig() when yaml.load() of the group.yaml content produces anything other than a plain mapping — null (empty document), a scalar, or an array. The loader uses the JSON_SCHEMA yaml schema, so the document must be a JSON-like object at the top level. It fires before any field validation, meaning the file's overall shape is wrong.
Solutions
- Make the document a top-level mapping with the required keys: version, name, repos (plus optional links/detect/matching).
- If the file looks empty, restore it from version control or re-create it from the documented group.yaml template.
- Validate locally before syncing: node -e "const y=require('js-yaml');const d=y.load(require('fs').readFileSync('group.yaml','utf8'),{schema:y.JSON_SCHEMA});console.log(typeof d, d&&typeof d==='object'&&!Array.isArray(d))".
Example fix
# before (group.yaml)
- repos:
services/api: https://github.com/org/api
# -> Error: Invalid YAML: expected an object
# after
version: 1
name: my-group
repos:
services/api: https://github.com/org/api Defensive patterns
Strategy: validation
Validate before calling
// Validate shape BEFORE loadGroupConfig so users get your message, not a raw throw.
import yaml from 'js-yaml';
export function prevalidateGroupYaml(content: string): void {
const doc = yaml.load(content, { schema: yaml.JSON_SCHEMA });
if (!doc || typeof doc !== 'object' || Array.isArray(doc)) {
throw new Error(
'group.yaml must be a mapping starting with keys like version/name/repos — ' +
'found ' + (doc === null ? 'an empty document' : typeof doc),
);
}
} Type guard
import yaml from 'js-yaml';
export const isGroupYamlObject = (content: string): boolean => {
try {
const doc = yaml.load(content, { schema: yaml.JSON_SCHEMA });
return !!doc && typeof doc === 'object' && !Array.isArray(doc);
} catch {
return false;
}
}; Try / catch
try {
config = await loadGroupConfig(groupDir);
} catch (err) {
if (err instanceof Error && err.message === 'Invalid YAML: expected an object') {
throw new Error(
`${groupDir}/group.yaml is not a YAML mapping. Start from:
version: 1
name: my-group
repos:
path/to/repo: <url>`,
{ cause: err },
);
}
throw err;
} Prevention
- Ship a minimal valid group.yaml template and generate new groups from it rather than hand-typing.
- Lint group.yaml in CI (yaml.load + shape check) so a mangled merge never reaches sync.
- Watch for merge-conflict artifacts: files left with only comments or a stray scalar fail this check.
When it happens
Trigger: Calling parseGroupConfig()/loadGroupConfig() on a group.yaml that is empty, contains only a comment, holds a bare scalar (e.g. just a group name), or whose top level is a YAML list (e.g. a repos list without the surrounding keys).
Common situations: Starting a group.yaml from a snippet that was only the repos block; truncating the file during a merge conflict resolution; pasting a markdown code fence into the file so the first token is a scalar.
Related errors
- links[ ].contract is required
- links[ ].from " " does not match any repo path in group
- links[ ].role " " is invalid. Expected: provider | consumer
- links[ ].to " " does not match any repo path in group
- links[ ].type " " is invalid. Expected
AI-assisted analysis of abhigyanpatwari/GitNexus@52924ef12c (2026-08-20).
Data as JSON: /api/errors/c3413814a3b9636d.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/core/group/config-parser.ts:51
http: true,
graphql: false,
grpc: true,
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}`,
);View on GitHub (pinned to 52924ef12c)