{"record":{"id":"a1fd45e90bbeec66","repo":"ruvnet/ruflo","slug":"no-models-available-to-build-validation-schema","errorCode":null,"errorMessage":"No models available to build validation schema","messagePattern":"No models available to build validation schema","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ruflo/src/ruvocal/src/lib/server/models.ts","lineNumber":198,"sourceCode":"export let defaultModel!: ProcessedModel;\nexport let taskModel!: ProcessedModel;\nexport let validModelIdSchema: z.ZodType<string> = z.string();\nexport let lastModelRefresh = new Date(0);\nexport let lastModelRefreshDurationMs = 0;\nexport let lastModelRefreshSummary: ModelsRefreshSummary = {\n\trefreshedAt: new Date(0),\n\tdurationMs: 0,\n\tadded: [],\n\tremoved: [],\n\tchanged: [],\n\ttotal: 0,\n};\n\nlet inflightRefresh: Promise<ModelsRefreshSummary> | null = null;\n\nconst createValidModelIdSchema = (modelList: ProcessedModel[]): z.ZodType<string> => {\n\tif (modelList.length === 0) {\n\t\tthrow new Error(\"No models available to build validation schema\");\n\t}\n\tconst ids = new Set(modelList.map((m) => m.id));\n\treturn z.string().refine((value) => ids.has(value), \"Invalid model id\");\n};\n\nconst resolveTaskModel = (modelList: ProcessedModel[]) => {\n\tif (modelList.length === 0) {\n\t\tthrow new Error(\"No models available to select task model\");\n\t}\n\n\tif (config.TASK_MODEL) {\n\t\tconst preferred = modelList.find(\n\t\t\t(m) => m.name === config.TASK_MODEL || m.id === config.TASK_MODEL\n\t\t);\n\t\tif (preferred) {\n\t\t\treturn preferred;\n\t\t}\n\t}","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/ruflo/src/ruvocal/src/lib/server/models.ts#L180-L216","documentation":"Thrown by createValidModelIdSchema when the supplied modelList is empty. The function builds a zod schema that validates user-supplied model ids against the currently-loaded set; with no models there is nothing to validate against. In practice applyModelState guards with the same empty check before calling this, so hitting it directly indicates createValidModelIdSchema was called from somewhere that did not pre-check emptiness.","triggerScenarios":"Direct call to createValidModelIdSchema([]); or a future code path that calls it before applyModelState has populated models. During normal startup the call is sequenced after buildModels and the applyModelState guard at models.ts:245, so it should be unreachable in production.","commonSituations":"A fork or refactor that invokes createValidModelIdSchema independently of applyModelState; tests that exercise the schema builder in isolation without seeding models; startup race where refreshModels is called before the initial buildModels resolves.","solutions":["Ensure createValidModelIdSchema is only called after confirming models.length > 0 (applyModelState already does this).","If calling it directly, pre-check the list and short-circuit or throw a more descriptive error.","In tests, seed a non-empty model list before exercising the schema builder."],"exampleFix":"// before\nvalidModelIdSchema = createValidModelIdSchema(models); // models may be []\n\n// after\nif (models.length === 0) {\n  // keep previous schema / log and skip reassignment\n} else {\n  validModelIdSchema = createValidModelIdSchema(models);\n}","handlingStrategy":"validation","validationCode":"function safeBuildSchema(models: ProcessedModel[]) {\n  if (models.length === 0) return z.string(); // or keep previous schema\n  return createValidModelIdSchema(models);\n}","typeGuard":"function hasModels<T extends { length: number }>(list: T): list is T & { length: number } {\n  return list.length > 0;\n}","tryCatchPattern":"try { validModelIdSchema = createValidModelIdSchema(models); }\ncatch (e) {\n  if (e instanceof Error && /No models available to build validation schema/.test(e.message)) {\n    validModelIdSchema = z.string(); // permissive fallback during empty state\n  } else throw e;\n}","preventionTips":["Only invoke createValidModelIdSchema after a non-empty check.","Keep applyModelState as the single caller so the empty guard at models.ts:245 always runs first.","In tests, seed models before exercising schema builders."],"tags":["models","validation","zod","startup","defensive"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}