yikart/AiToEarn · error · AppException
InvalidModel
InvalidModel
Error message
ResponseCode.InvalidModel
What it means
DraftGenerationPlannerService.planVideo resolves the planner model name (input.plannerModel or the configured default) and looks it up in config.ai.models.chat, requiring the entry to also have 'draft-generation' in its scenes array. If no such chat model config exists, it throws InvalidModel before any AI call is made.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/draft-generation/draft-generation-planner.service.ts:80
items: z.array(z.object({
text: z.string().min(1).max(120).describe('Short memory description'),
})).max(20),
})
export type AutoMemoryResult = z.infer<typeof AutoMemoryResultSchema>
@Injectable()
export class DraftGenerationPlannerService {
constructor(
private readonly aiAvailability: AiAvailabilityService,
@Optional() private readonly relayMediaResolver?: RelayMediaResolverService,
) {}
async planVideo(input: VideoPlanInput): Promise<{ plan: VideoDraftPlanResult, model: string }> {
const modelName = input.plannerModel ?? config.ai.draftGeneration.planner.defaultModel
const modelConfig = config.ai.models.chat.find(model => model.name === modelName && model.scenes?.includes('draft-generation'))
if (!modelConfig) {
throw new AppException(ResponseCode.InvalidModel)
}
const resolvedInput = await this.resolveReferenceUrls(input)
const prompt = this.buildVideoPrompt(resolvedInput)
const plan = await this.invokeStructuredPlanner(modelConfig, prompt, VideoDraftPlanResultSchema, resolvedInput.referenceImageUrls)
return { plan, model: modelConfig.name }
}
async planImageText(input: ImageTextPlanInput): Promise<{ plan: ImageTextDraftPlanResult, model: string }> {
const modelName = input.plannerModel ?? config.ai.draftGeneration.planner.defaultModel
const modelConfig = config.ai.models.chat.find(model => model.name === modelName && model.scenes?.includes('draft-generation'))
if (!modelConfig) {
throw new AppException(ResponseCode.InvalidModel)
}
const resolvedInput = await this.resolveReferenceUrls(input)
const prompt = this.buildImageTextPrompt(resolvedInput)
const plan = await this.invokeStructuredPlanner(modelConfig, prompt, ImageTextDraftPlanResultSchema, resolvedInput.referenceImageUrls)
if (plan.imagePrompts.length !== input.imageCount) {
plan.imagePrompts = Array.from({ length: input.imageCount }, (_, index) => plan.imagePrompts[index] ?? plan.imagePrompts[0] ?? input.userPrompt ?? '')View on GitHub (pinned to d3aa8bea5b)
Solutions
- Add the requested model to config.ai.models.chat with scenes including 'draft-generation', or pass a plannerModel that matches an existing entry
- Log the available chat model names/scenes at startup and compare with the requested modelName
- Validate input.plannerModel against the allowed model list in the DTO (Zod enum) before reaching the service
- Fix planner.defaultModel in config if the default itself is wrong
Example fix
// before (config)
models:
chat:
- name: gpt-4o
scenes: ['chat']
// after (config)
models:
chat:
- name: gpt-4o
scenes: ['chat', 'draft-generation'] Defensive patterns
Strategy: validation
Validate before calling
const modelName = input.plannerModel ?? config.ai.draftGeneration.planner.defaultModel
const valid = config.ai.models.chat.some(m => m.name === modelName && m.scenes?.includes('draft-generation'))
if (!valid) throw new Error(`Invalid planner model for draft-generation: ${modelName}`)
await plannerService.planVideo(input) Type guard
function isValidPlannerModel(name: string): boolean {
return config.ai.models.chat.some(m => m.name === name && m.scenes?.includes('draft-generation'))
} Try / catch
try {
const { plan, model } = await plannerService.planVideo(input)
} catch (e) {
if (e instanceof AppException && e.code === ResponseCode.InvalidModel) {
// fall back to the configured default planner
return plannerService.planVideo({ ...input, plannerModel: config.ai.draftGeneration.planner.defaultModel })
}
throw e
} Prevention
- Expose the valid model list to clients from config instead of hardcoding model names
- Add a Zod enum validation on plannerModel derived from config at the DTO layer
- Tag every intended planner model with scenes: ['draft-generation'] in config
- Add a startup check that planner.defaultModel resolves to a configured chat model
When it happens
Trigger: planVideo(input) is called with input.plannerModel set to a name not present in config.ai.models.chat, or present but whose scenes array does not include 'draft-generation'; or the default planner.defaultModel is missing/misnamed in the AI app config.
Common situations: Deployment config (yaml/env-derived config) never registered the chosen model under scenes ['draft-generation']; a model was renamed in the provider but not in app config; caller passes a raw provider model string that has no matching config entry; planner.defaultModel typo after a config refactor.
Related errors
- InvalidModel
- image aspectRatio cannot be converted to a supported size
- 代理地址不合法
- No subtitle entries in response
- No response from Gemini
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/399e0b9636b05c0b.
Report an issue: GitHub.