abhigyanpatwari/GitNexus · error · Error
expected a YAML object
Error message
expected a YAML object
What it means
parseAutoSyncConfig() loads the auto-sync YAML file with the JSON schema and requires the top-level document to be a plain object (mapping). It throws 'expected a YAML object' when the parsed document is null, a scalar, or an array — the auto-sync config format only supports a mapping at the root.
Source
Thrown at gitnexus/src/core/auto-sync/config.ts:114
message: `[auto-sync] Unable to read config file: ${configPath}. Auto sync is skipped.`,
};
}
try {
return { ok: true, config: parseAutoSyncConfig(content, configPath) };
} catch (err: unknown) {
return {
ok: false,
reason: 'invalid',
message: `[auto-sync] Invalid watch_config.yml: ${(err as Error).message}. Auto sync is skipped.`,
};
}
}
export function parseAutoSyncConfig(content: string, configPath: string): AutoSyncConfig {
const raw = yaml.load(content, { schema: yaml.JSON_SCHEMA }) as Record<string, unknown>;
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
throw new Error('expected a YAML object');
}
const errors: string[] = [];
const interval = Number(raw.sync_interval_minutes);
if (!Number.isInteger(interval) || interval <= 0) {
errors.push('sync_interval_minutes must be a positive integer');
} else if (interval < MIN_SYNC_INTERVAL_MINUTES) {
errors.push(`sync_interval_minutes must be at least ${MIN_SYNC_INTERVAL_MINUTES}`);
} else if (interval > MAX_SYNC_INTERVAL_MINUTES) {
errors.push(`sync_interval_minutes must not exceed ${MAX_SYNC_INTERVAL_MINUTES}`);
}
// YAML booleans survive JSON_SCHEMA (`true`/`false`). `Number(true) === 1`
// would otherwise pass the integer check and silently mean concurrency 1.
let maxConcurrency = DEFAULT_MAX_CONCURRENCY;
if (raw.max_concurrency !== undefined) {
if (typeof raw.max_concurrency !== 'number' || !Number.isInteger(raw.max_concurrency)) {
errors.push('max_concurrency must be a positive integer');View on GitHub (pinned to 0d1aed942f)
Solutions
- Make the top level a mapping, e.g. sync_interval_minutes: 30 at the root.
- Remove surrounding list syntax ('- ' items) or wrap entries under a top-level key.
- If the file is empty, populate it with the required keys (sync_interval_minutes at minimum).
- Validate the YAML parses to an object: node -e "console.log(require('js-yaml').load(require('fs').readFileSync(path,'utf8')))".
Example fix
// before - repo: git@github.com:org/repo.git // after sync_interval_minutes: 30 remotes: - git@github.com:org/repo.git
Defensive patterns
Strategy: validation
Validate before calling
const yaml = require('js-yaml');
const doc = yaml.load(fs.readFileSync(cfgPath, 'utf8'), { schema: yaml.JSON_SCHEMA });
if (!doc || typeof doc !== 'object' || Array.isArray(doc)) throw new Error('auto-sync config must be a YAML mapping'); Type guard
const isRecord = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);
Prevention
- Ensure the config's top level is a key: value mapping, not a list
- Don't leave the config file empty — an empty YAML parses to null
- Lint the YAML with a parser before saving
When it happens
Trigger: A .gitnexus auto-sync config file whose content parses to a list (e.g. starts with '-'), an empty file (yaml.load returns null), or a bare scalar like just a number or quoted string.
Common situations: Accidentally pasting a YAML list of repos instead of a mapping, an empty config file created by touch, or YAML that's just a comment so it parses to null.
Related errors
- Invalid YAML: expected an object
- version is required in group.yaml
- Unsupported group.yaml version: ${raw.version}. Expected 1.
- name is required in group.yaml
- links[${i}].from "${link.from}" does not match any repo path
AI-assisted analysis of abhigyanpatwari/GitNexus@0d1aed942f (2026-09-08).
Data as JSON: /api/errors/66236ca6b943f722.
Report an issue: GitHub.