{"record":{"id":"3c4aab493877ab84","repo":"paperclipai/paperclip","slug":"path-must-be-a-non-empty-string","errorCode":null,"errorMessage":"${path} must be a non-empty string","messagePattern":"(.+?) must be a non-empty string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/cli/eval-session-contract.ts","lineNumber":103,"sourceCode":"  agentTurns: number;\n  providerRequests: number;\n  inputTokens: number;\n  outputTokens: number;\n  cachedInputTokens: number;\n  reasoningTokens: number;\n  providerReportedCostNanodollars: number;\n}\n\nfunction object(value: unknown, path: string): Record<string, unknown> {\n  if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n    throw new Error(`${path} must be an object`);\n  }\n  return value as Record<string, unknown>;\n}\n\nfunction text(value: unknown, path: string): string {\n  if (typeof value !== \"string\" || value.trim().length === 0) {\n    throw new Error(`${path} must be a non-empty string`);\n  }\n  return value;\n}\n\nfunction positiveInteger(value: unknown, path: string): number {\n  if (!Number.isSafeInteger(value) || Number(value) <= 0) {\n    throw new Error(`${path} must be a positive safe integer`);\n  }\n  return Number(value);\n}\n\nexport function expectedEvalSessionDriver(\n  provider: EvalSessionProvider,\n): EvalSessionDriver {\n  return provider === \"opencode\"\n    ? \"opencode_server\"\n    : provider === \"claude_managed\"\n      ? \"claude_managed_agents_api\"","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/cli/eval-session-contract.ts#L85-L121","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Populate the field named in the error path with a non-empty trimmed string","Check the producer/config for empty template interpolation or missing keys","Add the missing key to the request payload per the eval-session schema","If the field is genuinely optional upstream, stop routing it through this required-field contract"],"exampleFix":"// before\nconst req = { schema: SCHEMA, managedProfile: { betaVersion: 'managed-agents-2026-04-01', agentVersion: '' } };\n// after\nconst req = { schema: SCHEMA, managedProfile: { betaVersion: 'managed-agents-2026-04-01', agentVersion: '42' } };","handlingStrategy":"validation","validationCode":"function requireNonEmptyString(v, name) {\n  if (typeof v !== 'string' || v.trim().length === 0) throw new Error(`${name} must be a non-empty string`);\n  return v;\n}\nrequireNonEmptyString(req.managedProfile?.agentVersion, 'agentVersion');","typeGuard":"function isNonEmptyString(v) {\n  return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":"try {\n  const request = parseEvalSessionRequest(raw);\n} catch (err) {\n  if (err.message.includes('must be a non-empty string')) {\n    const field = err.message.split(' ')[0];\n    throw new RequestValidationError(`Missing required field: ${field}`, { cause: err });\n  }\n  throw err;\n}","preventionTips":["Validate all identifier fields at request-construction time, not at the boundary","Guard against empty template interpolation in config-driven payloads","Run a pre-submission check that trims and asserts every required string","Keep field names in sync with the contract after renames (use exported constants where possible)"],"tags":["validation","contract","empty-string"],"backgroundTag":"schema-validation-failed","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-02T18:44:00.616Z","contentChangedAt":"2026-09-02T18:44:00.616Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}