ruvnet/ruflo · error · Error

repository harness descriptor requires a non-empty harnessId

Error message

repository harness descriptor requires a non-empty harnessId

What it means

normalizeHarnessDescriptor accepts either a modern HarnessDescriptor (harnessId) or a legacy descriptor (name) and downgrades it to the safe v1 baseline. The id resolution (input.harnessId ?? input.name) must yield a non-empty trimmed string; undefined, '', or whitespace-only values throw. The function deliberately strips 'release-decisions' and unknown capabilities — this error is purely about the missing identifier.

Source

Thrown at v3/@claude-flow/codex/src/harness/contract.ts:196

  'message-acknowledgement',
  'run-evidence',
  'exact-source-state',
  'release-decisions',
]);

/**
 * Convert an older descriptor to the safe v1 reference baseline.
 *
 * Unknown and authority-bearing capabilities are ignored. A legacy descriptor
 * can never self-assert enforce or release authority through this compatibility
 * function. A separately verified external adapter is required for that.
 */
export function normalizeHarnessDescriptor(
  input: HarnessDescriptor | LegacyHarnessDescriptor,
): InMemoryReferenceHarnessDescriptor {
  const harnessId = input.harnessId ?? ('name' in input ? input.name : undefined);
  if (typeof harnessId !== 'string' || harnessId.trim().length === 0) {
    throw new Error('repository harness descriptor requires a non-empty harnessId');
  }

  const requested = Array.isArray(input.capabilities) ? input.capabilities : [];
  const capabilities: Array<Exclude<HarnessCapability, 'release-decisions'>> = [...new Set(
    requested.filter((value): value is HarnessCapability => (
      CAPABILITIES.has(value as HarnessCapability)
      && value !== 'release-decisions'
    )),
  )] as Array<Exclude<HarnessCapability, 'release-decisions'>>;
  capabilities.sort();

  return {
    contractVersion: 1,
    harnessId: harnessId.trim(),
    mode: 'observe',
    capabilities,
    advisory: true,
    assurance: 'in-memory-reference',

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Set harnessId to a stable non-empty identifier on the descriptor
  2. For legacy descriptors, populate the name field — it is accepted as the id
  3. Validate descriptors right after deserialization and before calling normalizeHarnessDescriptor so failures carry file/field context

Example fix

// before
const descriptor = { capabilities: ['coordination'] }; // no harnessId or name
normalizeHarnessDescriptor(descriptor); // throws

// after
const descriptor = { harnessId: 'my-harness', capabilities: ['coordination'] };
// or the legacy shape:
const legacy = { name: 'my-harness', capabilities: ['coordination'] };
Defensive patterns

Strategy: validation

Validate before calling

function hasHarnessIdentifier(d: Partial<{ harnessId: string; name: string }>): boolean {
  const id = d.harnessId ?? d.name;
  return typeof id === 'string' && id.trim().length > 0;
}

Type guard

function isDescriptorWithId(d: unknown): d is { harnessId: string } | { name: string } {
  if (typeof d !== 'object' || d === null) return false;
  const rec = d as Record<string, unknown>;
  const id = rec.harnessId ?? rec.name;
  return typeof id === 'string' && id.trim().length > 0;
}

Try / catch

Catch around normalizeHarnessDescriptor during config load and report the source file/key of the offending descriptor; fail startup rather than defaulting the id, since a blank id would make harness sessions unaddressable.

Prevention

When it happens

Trigger: Passing a descriptor with neither harnessId nor name; harnessId set to '' or ' '; a legacy shape whose name key was removed; a spread of defaults that overwrites harnessId with an empty string.

Common situations: Loading harness descriptors from JSON configs where the key was renamed from name to harnessId and older files lack the new field; optional-chaining chains producing undefined; YAML parsers turning an empty value into ''.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/745df4db44f2d31e. Report an issue: GitHub.