{"record":{"id":"09eab2d48e5acaac","repo":"ruvnet/ruflo","slug":"field-key-must-be-a-non-empty-string","errorCode":null,"errorMessage":"field \"${key}\" must be a non-empty string","messagePattern":"field \"(.+?)\" must be a non-empty string","errorType":"validation","errorClass":"PodTemplateValidationError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/business-pods/pod-schema.ts","lineNumber":96,"sourceCode":" * callers can render a precise message.\n */\nexport class PodTemplateValidationError extends Error {\n  constructor(message: string, public path: string) {\n    super(`pod-template at ${path}: ${message}`);\n    this.name = 'PodTemplateValidationError';\n  }\n}\n\nconst PII_POLICIES: PiiPolicy[] = ['soc2', 'gdpr', 'hipaa', 'permissive'];\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\nfunction requireString(parent: Record<string, unknown>, key: string, path: string): string {\n  const v = parent[key];\n  if (typeof v !== 'string' || v.length === 0) {\n    throw new PodTemplateValidationError(`field \"${key}\" must be a non-empty string`, path);\n  }\n  return v;\n}\n\nfunction requireNumber(parent: Record<string, unknown>, key: string, path: string): number {\n  const v = parent[key];\n  if (typeof v !== 'number' || !Number.isFinite(v)) {\n    throw new PodTemplateValidationError(`field \"${key}\" must be a finite number`, path);\n  }\n  return v;\n}\n\nfunction requireBoolean(parent: Record<string, unknown>, key: string, path: string): boolean {\n  const v = parent[key];\n  if (typeof v !== 'boolean') {\n    throw new PodTemplateValidationError(`field \"${key}\" must be a boolean`, path);\n  }\n  return v;","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/business-pods/pod-schema.ts#L78-L114","documentation":"Pod template validator's requireString() throws PodTemplateValidationError when a required string field is missing, not a string, or an empty string. The error carries the JSON pointer path (rendered as 'pod-template at <path>: ...') so you can locate the offending key inside plugins/ruflo-business-pods/templates/*.json.","triggerScenarios":"validatePodTemplate() on a template where any required string field (name, displayName, roomId, agents[].role/agentType/description, bench.name/description, cronSchedule, ...) is absent, null, a number, or \"\". The failing key name is interpolated into the message.","commonSituations":"Hand-edited pod template JSON with a typo'd key (displayname vs displayName); template copied from docs that omitted optional-looking fields; agents entries reduced to plain strings instead of objects; trailing whitespace-only values are NOT caught (only empty), but outright missing keys are.","solutions":["Read the path in the error: it names the exact field and its location — add/fix that key in the template JSON","Cross-check against the PodTemplate interface in pod-schema.ts for the full required-field list","Validate templates in CI before shipping: run the validator as a lint step so typos never deploy","Don't rely on TypeScript — templates are runtime JSON, so runtime validation is the only gate"],"exampleFix":"// before\n{ \"name\": \"sales\", \"roomId\": \"sales\", \"displayName\": \"\" }\n// after\n{ \"name\": \"sales\", \"roomId\": \"sales\", \"displayName\": \"Sales Pipeline Pod\" }","handlingStrategy":"validation","validationCode":"// Pre-flight a template before registering it\ntry {\n  validatePodTemplate(JSON.parse(fs.readFileSync(tplPath, 'utf8')));\n} catch (e) {\n  if (e instanceof PodTemplateValidationError) fail(`${tplPath}: ${e.message}`);\n  throw e;\n}","typeGuard":"function hasNonEmptyString(o: Record<string, unknown>, key: string): boolean {\n  return typeof o[key] === 'string' && (o[key] as string).length > 0;\n}","tryCatchPattern":"try {\n  validatePodTemplate(template);\n} catch (e) {\n  if (e instanceof PodTemplateValidationError) {\n    // e.path is a JSON pointer to the exact offending field\n    reportTemplateIssue(e.path, e.message);\n  } else throw e;\n}","preventionTips":["Run validatePodTemplate as a CI lint step over every template in plugins/ruflo-business-pods/templates/","Author templates from the PodTemplate interface, not from memory","Use the error's JSON pointer path rather than eyeballing the whole file"],"tags":["pod","schema","validation","json","business-pods"],"backgroundTag":"schema-validation-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}