abhigyanpatwari/GitNexus · error · Error

links[${i}].contract is required

Error message

links[${i}].contract is required

What it means

Thrown during links[] validation when a link's 'contract' field is undefined, null, or trims to an empty string. The contract field carries the contract identifier (e.g. an HTTP route like 'GET /v1/users', a grpc method fully-qualified name, a topic name). It is required because a link without a contract binds no actual consumer-provider relationship.

Source

Thrown at gitnexus/src/core/group/config-parser.ts:87

      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 ContractType)) {
      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 ContractType,
      contract: String(link.contract),
      role: link.role as ContractRole,
    };
  });

  const detect = { ...DEFAULT_DETECT, ...((raw.detect as object) || {}) };
  const matching = { ...DEFAULT_MATCHING, ...((raw.matching as object) || {}) };
  const packages = (raw.packages as Record<string, Record<string, string>>) || {};

  return {
    version: 1,
    name: raw.name as string,
    description: (raw.description as string) || '',

View on GitHub (pinned to d540b00184)

Solutions

  1. Set link.contract to a non-empty string describing the actual contract: an HTTP route (e.g. 'GET /v1/users'), a grpc method (e.g. 'pkg.Svc/Method'), a topic name, or a library/include identifier.
  2. If the contract isn't known yet, remove the entire link entry — partial links are not allowed.

Example fix

# before — empty placeholder contract
links:
  - { from: services/api, to: services/worker, type: http, contract: '', role: provider }

# after
links:
  - { from: services/api, to: services/worker, type: http, contract: 'GET /v1/users', role: provider }
Defensive patterns

Strategy: validation

Validate before calling

function hasNonEmptyContract(link: Record<string, unknown>): boolean {
  return link.contract !== undefined && link.contract !== null &&
    typeof link.contract === 'string' && link.contract.trim().length > 0;
}

Type guard

function linkHasContract(link: unknown): link is { contract: string } {
  return typeof (link as Record<string, unknown>)?.contract === 'string' &&
    ((link as Record<string, unknown>).contract as string).trim().length > 0;
}

Prevention

When it happens

Trigger: A link missing the 'contract' key; contract: null; contract: '' or contract: ' ' (whitespace-only).

Common situations: Hand-authored link left with a placeholder empty contract; the contract field accidentally deleted during edit; a template with contract: TODO that was never filled in.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/c193a177a6557bd0. Report an issue: GitHub.