{"record":{"id":"d6406eb53376f2dd","repo":"plandex-ai/plandex","slug":"error-deleting-custom-models-w","errorCode":null,"errorMessage":"error deleting custom models: %w","messagePattern":"error deleting custom models: %w","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/models.go","lineNumber":311,"sourceCode":"\t\t\t\treturn fmt.Errorf(\"error creating custom model: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tfor _, provider := range toUpsertCustomProviders {\n\t\t\tif err := db.UpsertCustomProvider(tx, provider); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating custom provider: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tfor _, modelPack := range toUpsertModelPacks {\n\t\t\tif err := db.UpsertModelPack(tx, modelPack); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating model pack: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif len(toDeleteCustomModelIds) > 0 {\n\t\t\tif err := db.DeleteCustomModels(tx, auth.OrgId, toDeleteCustomModelIds); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error deleting custom models: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif len(toDeleteCustomProviderIds) > 0 {\n\t\t\tif err := db.DeleteCustomProviders(tx, auth.OrgId, toDeleteCustomProviderIds); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error deleting custom providers: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif len(toDeleteModelPackIds) > 0 {\n\t\t\tif err := db.DeleteModelPacks(tx, auth.OrgId, toDeleteModelPackIds); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error deleting model packs: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/models.go#L293-L329","documentation":"Wrapped error raised inside the org model-import transaction (CreateCustomModelsHandler) when db.DeleteCustomModels fails while removing org custom models that no longer appear in the submitted config. Because it runs in a db.WithTx closure, the failure aborts the whole upsert/delete transaction and the handler returns 500 'Failed to import custom models/providers/model packs'.","triggerScenarios":"POST of a custom models/providers/model packs config where existing custom models for the org are absent from the payload, and db.DeleteCustomModels(tx, auth.OrgId, toDeleteCustomModelIds) returns a DB error (connection loss, FK constraint from a model still referenced by a model pack, deadlock, tx already aborted).","commonSituations":"Deleting a custom model that is still referenced by an existing model pack or plan config; Postgres connection pool exhaustion; concurrent config imports from two clients racing on the same org's custom models.","solutions":["Ensure no model pack or default config still references the custom models being deleted (delete/repoint dependent packs first, or add ON DELETE CASCADE to the FK)","Inspect the wrapped %w error in server logs to identify the exact Postgres error (constraint name, deadlock, connection)","Retry the import after resolving conflicts; the whole transaction rolled back so state is unchanged","Check DB connectivity/pool settings if the underlying error is a connection error"],"exampleFix":"// before: models referencing a pack fail FK delete\nconfig.CustomModels = remainingModels\nclient.ImportCustomModels(config)\n// after: drop dependent packs in the same payload\nconfig.CustomModelPacks = packsThatDontUseDeletedModels\nclient.ImportCustomModels(config)","handlingStrategy":"validation","validationCode":"// client-side: keep every referenced custom model in the payload\nconst modelIds = new Set(config.CustomModels.map(m => m.ModelId))\nfor (const pack of config.ModelPacks ?? []) {\n  for (const role of ['planner','coder','summarizer']) {\n    const p = pack[role];\n    if (p && !modelIds.has(p.modelId)) throw new Error(`pack ${pack.Name} references missing model ${p.modelId}`)\n  }\n}","typeGuard":"function hasAllModels(config) {\n  const ids = new Set((config.CustomModels ?? []).map(m => String(m.ModelId)))\n  return (config.ModelPacks ?? []).every(pack =>\n    ['planner','coder','summarizer'].every(role =>\n      !pack[role] || ids.has(pack[role].modelId)))\n}","tryCatchPattern":"try {\n  await client.ImportCustomModels(config)\n} catch (err) {\n  if (String(err.message).includes('error deleting custom models')) {\n    // rollback happened; re-add missing models or drop dependent packs, then retry\n  }\n}","preventionTips":["Never omit existing custom models from an import payload unless their references are removed too","Delete dependent model packs before deleting the custom models they use","Retry imports idempotently — the transaction rolls back cleanly on failure"],"tags":["database","transaction","foreign-key"],"backgroundTag":"db-transaction-aborted","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}