paperclipai/paperclip · error · Error

${path} must be a non-empty string

Error message

${path} must be a non-empty string

What it means

The text() helper validates that a field at a given path is a string with non-empty trimmed content. It throws '<path> must be a non-empty string' when the value is missing, not a string, or only whitespace. Used for required identifiers like agentVersion and profileId in eval-session profiles.

Source

Thrown at packages/paperclip-runner/src/cli/eval-session-contract.ts:103

  agentTurns: number;
  providerRequests: number;
  inputTokens: number;
  outputTokens: number;
  cachedInputTokens: number;
  reasoningTokens: number;
  providerReportedCostNanodollars: number;
}

function object(value: unknown, path: string): Record<string, unknown> {
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
    throw new Error(`${path} must be an object`);
  }
  return value as Record<string, unknown>;
}

function text(value: unknown, path: string): string {
  if (typeof value !== "string" || value.trim().length === 0) {
    throw new Error(`${path} must be a non-empty string`);
  }
  return value;
}

function positiveInteger(value: unknown, path: string): number {
  if (!Number.isSafeInteger(value) || Number(value) <= 0) {
    throw new Error(`${path} must be a positive safe integer`);
  }
  return Number(value);
}

export function expectedEvalSessionDriver(
  provider: EvalSessionProvider,
): EvalSessionDriver {
  return provider === "opencode"
    ? "opencode_server"
    : provider === "claude_managed"
      ? "claude_managed_agents_api"

View on GitHub (pinned to 01ad858492)

Solutions

  1. Populate the field named in the error path with a non-empty trimmed string
  2. Check the producer/config for empty template interpolation or missing keys
  3. Add the missing key to the request payload per the eval-session schema
  4. If the field is genuinely optional upstream, stop routing it through this required-field contract

Example fix

// before
const req = { schema: SCHEMA, managedProfile: { betaVersion: 'managed-agents-2026-04-01', agentVersion: '' } };
// after
const req = { schema: SCHEMA, managedProfile: { betaVersion: 'managed-agents-2026-04-01', agentVersion: '42' } };
Defensive patterns

Strategy: validation

Validate before calling

function requireNonEmptyString(v, name) {
  if (typeof v !== 'string' || v.trim().length === 0) throw new Error(`${name} must be a non-empty string`);
  return v;
}
requireNonEmptyString(req.managedProfile?.agentVersion, 'agentVersion');

Type guard

function isNonEmptyString(v) {
  return typeof v === 'string' && v.trim().length > 0;
}

Try / catch

try {
  const request = parseEvalSessionRequest(raw);
} catch (err) {
  if (err.message.includes('must be a non-empty string')) {
    const field = err.message.split(' ')[0];
    throw new RequestValidationError(`Missing required field: ${field}`, { cause: err });
  }
  throw err;
}

Prevention

When it happens

Trigger: Any required string field validated via text() — e.g. request.managedProfile.agentVersion, request.managedProfile.profileId, request.agentCoreProfile.profileId/region — is undefined, null, a non-string type, or ""/whitespace-only.

Common situations: Caller omits an identifier field; a template variable interpolates to empty; upstream returns null for a profile id; field renamed so the key no longer matches.

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 paperclipai/paperclip@01ad858492 (2026-09-02). Data as JSON: /api/errors/3c4aab493877ab84. Report an issue: GitHub.