linshenkx/prompt-optimizer · error · EvaluationValidationError

${label} id must not be empty.

Error message

${label} id must not be empty.

What it means

Every test case in an evaluation must have a non-empty id so results can be correlated back to inputs. validateTestCase throws when testCase.id is missing or whitespace — the message includes the label passed by the caller (e.g. 'Test case #3') to identify the offending case.

Source

Thrown at packages/core/src/services/evaluation/service.ts:1714

    if (!block) {
      throw new EvaluationValidationError(`${label} must not be empty.`);
    }
    if (!block.label?.trim()) {
      throw new EvaluationValidationError(`${label} label must not be empty.`);
    }
    const hasContent = !!block.content?.trim();
    const hasMedia = this.hasBlockMedia(block);
    if (!hasContent && !hasMedia) {
      throw new EvaluationValidationError(`${label} content must not be empty.`);
    }
    if (block.media) {
      this.validateMediaItems(block.media, `${label} media`);
    }
  }

  private validateTestCase(testCase: EvaluationTestCase | undefined, label: string): void {
    if (!testCase?.id?.trim()) {
      throw new EvaluationValidationError(`${label} id must not be empty.`);
    }
    this.validateContentBlock(testCase.input, `${label} input`);
  }

  private validateSnapshot(snapshot: EvaluationSnapshot | undefined, label: string): void {
    if (!snapshot?.id?.trim()) {
      throw new EvaluationValidationError(`${label} id must not be empty.`);
    }
    if (!snapshot?.label?.trim()) {
      throw new EvaluationValidationError(`${label} label must not be empty.`);
    }
    if (!snapshot?.testCaseId?.trim()) {
      throw new EvaluationValidationError(`${label} testCaseId must not be empty.`);
    }
    if (!snapshot?.promptText?.trim()) {
      throw new EvaluationValidationError(`${label} promptText must not be empty.`);
    }
    if (!snapshot?.output?.trim()) {

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Assign a unique non-empty string id to every test case before submission
  2. Use the error message's label to find the exact entry and fix it
  3. Generate ids deterministically (e.g. slug or uuid) during import if the source lacks them

Example fix

// before
testCases: [{ input: { label: 'p', content: 'hi' } }]

// after
testCases: [{ id: 'tc-001', input: { label: 'p', content: 'hi' } }]
Defensive patterns

Strategy: validation

Validate before calling

import { randomUUID } from 'node:crypto';

function ensureTestCaseIds(testCases: { id?: string }[]): void {
  testCases.forEach((tc, i) => {
    if (!tc.id?.trim()) tc.id = `tc-${i + 1}-${randomUUID().slice(0, 8)}`;
  });
}

Type guard

const hasTestCaseId = (tc: { id?: string } | undefined): boolean => !!tc?.id?.trim();

Try / catch

try {
  await evaluationService.create(request);
} catch (err) {
  if (err instanceof EvaluationValidationError && /id must not be empty/.test(err.message)) {
    assignIdsAndRetry();
  } else throw err;
}

Prevention

When it happens

Trigger: Submitting an evaluation whose testCases array contains an entry with no id, an empty id, or an id of spaces. Typically from generated or imported test case lists.

Common situations: CSV/JSON import where the id column is blank; array index used as id but off-by-one left it undefined; deduplication code deleting ids; id field renamed during a schema migration.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/5a74d6e1f602f9d3. Report an issue: GitHub.