{"record":{"id":"5b8c6bc377d237b0","repo":"linshenkx/prompt-optimizer","slug":"modelmanager-modelidgeneratefailed","errorCode":null,"errorMessage":"modelManager.modelIdGenerateFailed","messagePattern":"modelManager\\.modelIdGenerateFailed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/src/composables/model/useTextModelManager.ts","lineNumber":864,"sourceCode":"  }\n\n  const createNewModel = async () => {\n    // Auto-generate a stable internal id for the config.\n    // Text models use the id as the storage key and runtime selector.\n    const providerId = form.value.providerId || 'custom'\n    // Extremely unlikely, but avoid collisions with built-in keys or existing custom configs.\n    let modelKey = ''\n    for (let attempt = 0; attempt < 5; attempt++) {\n      const candidate = generateTextModelId(providerId, attempt)\n      const existingModel = await modelManager.getModel(candidate)\n      if (!existingModel && !isDefaultModel(candidate)) {\n        modelKey = candidate\n        break\n      }\n    }\n\n    if (!modelKey) {\n      throw new Error(t('modelManager.modelIdGenerateFailed'))\n    }\n\n    const { providerMeta, modelMeta } = resolveFormMetadata(\n      form.value.providerId,\n      form.value.defaultModel || form.value.modelId\n    )\n\n    const connectionConfig: TextConnectionConfig = {\n      ...form.value.connectionConfig\n    }\n    if (form.value.displayMaskedKey && form.value.originalApiKey) {\n      connectionConfig.apiKey = form.value.originalApiKey\n    }\n    normalizeConnectionCustomHeaders(connectionConfig)\n\n    const newConfig = {\n      id: modelKey,\n      name: form.value.name,","sourceCodeStart":846,"sourceCodeEnd":882,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/ui/src/composables/model/useTextModelManager.ts#L846-L882","documentation":"createNewModel generates a unique model key by trying candidates derived from the model id/name; if every candidate collides with an existing model key, modelKey stays empty and it throws modelManager.modelIdGenerateFailed. The slug/candidate generator plus a uniqueness loop could not produce a free id.","triggerScenarios":"Creating a model whose id candidates all already exist (e.g. many duplicates named the same so candidate-1..N are exhausted), or the candidate sanitizer stripping the id to an empty string so no valid key is produced. Typically requires many same-named models or an id made entirely of invalid characters.","commonSituations":"Bulk import creating dozens of identically named models; model id containing only whitespace/symbols that sanitize to ''; a loop bug where candidates are never incremented; hitting an artificial cap on collision retries.","solutions":["Rename the model id / provider+model combination so it is unique","Increase or fix the candidate suffix loop (ensure it appends -1, -2, ... and has a sane bound)","Sanitize before generating: if the cleaned base id is empty, reject early with a clear validation message","Delete duplicate same-named models that are no longer needed"],"exampleFix":"// before\nif (!modelKey) {\n  throw new Error(t('modelManager.modelIdGenerateFailed'))\n}\n\n// after\nif (!modelKey) {\n  const fallback = `${sanitizedBase || 'model'}-${Date.now().toString(36)}`\n  modelKey = fallback\n}","handlingStrategy":"validation","validationCode":"const base = sanitizeModelId(form.value.modelId)\nif (!base) { /* require a valid model id before save */ }\nconst taken = new Set(models.value.map((m) => m.id))\nif (taken.has(base) && !isEdit) { /* pick a different name */ }","typeGuard":"const isValidModelKey = (k: unknown): k is string => typeof k === 'string' && /^[a-z0-9][a-z0-9-_]*$/i.test(k)","tryCatchPattern":"try { await createNewModel() } catch (e) { if (/modelIdGenerateFailed/.test(String(e?.message))) { form.value.modelId = `${form.value.modelId}-${Date.now().toString(36)}`; await createNewModel() } else throw e }","preventionTips":["Use unique, descriptive model ids","Sanitize ids early and reject empty results","Bound and verify the collision-retry loop"],"tags":["model-manager","id-generation","slug-collision"],"backgroundTag":"unique-id-generation-failed","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}