abhigyanpatwari/GitNexus · error · Error
links[ ].role " " is invalid. Expected: provider | consumer
Error message
links[${i}].role "${link.role}" is invalid. Expected: provider | consumer What it means
Thrown while validating a group.yaml links entry: the link's `role` is not exactly 'provider' or 'consumer' — the only two valid roles. Role records which side of the contract this link describes (the repo in `from` exposing vs consuming the interface), which the contract matching step relies on.
Solutions
- Set role to exactly `provider` or `consumer` (lowercase, singular), describing the `from` repo's relation to the contract.
- For a from-repo that implements/exposes the interface use provider; for one that calls it use consumer.
- Check every link — the validator stops at the first bad entry, so fix iteratively or lint the whole file.
Example fix
# before (group.yaml)
links:
- from: services/api
to: services/web
type: http
role: server
# -> Error: links[0].role "server" is invalid. Expected: provider | consumer
# after
links:
- from: services/api
to: services/web
type: http
role: provider Defensive patterns
Strategy: validation
Validate before calling
import yaml from 'js-yaml';
const VALID_ROLES = ['provider', 'consumer'];
export function validateLinkRoles(content: string): void {
const doc = yaml.load(content, { schema: yaml.JSON_SCHEMA }) as Record<string, any>;
(doc.links ?? []).forEach((link: any, i: number) => {
if (!VALID_ROLES.includes(link?.role)) {
throw new Error(
`links[${i}].role must be 'provider' or 'consumer' (describing the \`from\` repo) — got ${JSON.stringify(link?.role)}`,
);
}
});
} Type guard
export const isContractRole = (r: unknown): r is 'provider' | 'consumer' => r === 'provider' || r === 'consumer';
Try / catch
try {
config = await loadGroupConfig(groupDir);
} catch (err) {
if (err instanceof Error && /links\[\d+\]\.role .* is invalid/.test(err.message)) {
throw new Error(
'link role must be exactly provider or consumer (lowercase), describing the from-repo',
{ cause: err },
);
}
throw err;
} Prevention
- Memorize the semantics: role describes the from repo — provider if it exposes the contract, consumer if it calls it.
- Do not use client/server/exposes vocabulary; the schema accepts only provider|consumer.
- Validate the entire links array up front so one bad role does not surface per sync iteration.
When it happens
Trigger: A links[i].role that is missing, misspelled (providor, consumes), pluralized (providers), or uses a different vocabulary (server, client).
Common situations: Thinking role describes the `to` repo and writing client/server; auto-completing to provider/consumer variants; omitting role on some links while copying others.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- links[ ].type " " is invalid. Expected
- links[ ].contract is required
- links[ ].from " " does not match any repo path in group
- links[ ].to " " does not match any repo path in group
- Invalid YAML: expected an object
AI-assisted analysis of abhigyanpatwari/GitNexus@52924ef12c (2026-08-20).
Data as JSON: /api/errors/e91e656f3b94edcb.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/core/group/config-parser.ts:90
}
const repoPaths = new Set(Object.keys(repos));
const rawLinks = (raw.links as unknown[]) || [];
const links: GroupManifestLink[] = rawLinks.map((l: unknown, i: number) => {
const link = l as Record<string, unknown>;
if (!link.from || !repoPaths.has(link.from as string)) {
throw new Error(`links[${i}].from "${link.from}" does not match any repo path in group`);
}
if (!link.to || !repoPaths.has(link.to as string)) {
throw new Error(`links[${i}].to "${link.to}" does not match any repo path in group`);
}
if (!VALID_CONTRACT_TYPES.includes(link.type as ManifestContractType)) {
throw new Error(
`links[${i}].type "${link.type}" is invalid. Expected: ${VALID_CONTRACT_TYPES.join(', ')}`,
);
}
if (!VALID_ROLES.includes(link.role as ContractRole)) {
throw new Error(`links[${i}].role "${link.role}" is invalid. Expected: provider | consumer`);
}
if (
link.contract === undefined ||
link.contract === null ||
String(link.contract).trim() === ''
) {
throw new Error(`links[${i}].contract is required`);
}
return {
from: link.from as string,
to: link.to as string,
type: link.type as ManifestContractType,
contract: String(link.contract),
role: link.role as ContractRole,
};
});
const rawDetect = raw.detect;View on GitHub (pinned to 52924ef12c)