{"record":{"id":"a169e6e26bcbcc1a","repo":"Billionmail/BillionMail","slug":"cannot-delete-the-system-s-built-in-model-supplier","errorCode":null,"errorMessage":"Cannot delete the system's built-in model supplier.","messagePattern":"Cannot delete the system's built-in model supplier\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/supplier.go","lineNumber":630,"sourceCode":"\t\tSort:            100, // Default sort order, can be changed later\n\t\tIcon:            \"\",  // Default icon, can be set later\n\t}\n\n\treturn SaveSupplierConfig(supplierName, supplier)\n}\n\n// RemoveSupplier deletes a supplier's configuration directory and all its contents.\n// It checks if the supplier exists, and if so, it removes the directory and its files\n// If the supplier does not exist, it returns an error indicating that the supplier cannot be found.\n// This function is useful for cleaning up unused suppliers from the configuration.\nfunc RemoveSupplier(supplierName string) error {\n\tsupplierPath := SUPPLIER_CONFIG_PATH + \"/\" + supplierName\n\tif !public.FileExists(supplierPath) {\n\t\treturn errors.New(\"supplier does not exist\")\n\t}\n\ttemplatePath := SUPPLIER_TEMPLATE_PATH + \"/\" + supplierName\n\tif public.FileExists(templatePath) {\n\t\treturn errors.New(\"Cannot delete the system's built-in model supplier.\")\n\t}\n\n\terr := os.RemoveAll(supplierPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// SetModelTitle updates the title of a model in the supplier's models.json file.\n// It reads the existing models, modifies the title of the specified model, and saves the updated list back to the file.\n// If the model is not found, it returns an error indicating that the model does not exist.\nfunc SetModelTitle(supplierName string, modelId string, title string) error {\n\tmodelsFile := SUPPLIER_CONFIG_PATH + \"/\" + supplierName + \"/models.json\"\n\tif !public.FileExists(modelsFile) {\n\t\treturn errors.New(\"models file does not exist for supplier: \" + supplierName)\n\t}","sourceCodeStart":612,"sourceCodeEnd":648,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/supplier.go#L612-L648","documentation":"RemoveSupplier refuses to delete a supplier whose name also exists under SUPPLIER_TEMPLATE_PATH, because such suppliers are system built-ins shipped with the application. Deleting them would break default functionality and they would be restored on upgrade anyway.","triggerScenarios":"Calling RemoveSupplier on any built-in supplier (one that has a directory under SUPPLIER_TEMPLATE_PATH), even though its config directory exists.","commonSituations":"Trying to clean up 'unused' suppliers that are actually default built-ins; scripting bulk deletion of all suppliers; users wanting to reset a built-in supplier's credentials.","solutions":["Only remove custom suppliers — list SUPPLIER_CONFIG_PATH entries that have no counterpart in SUPPLIER_TEMPLATE_PATH and skip built-ins","If the goal is to disable a built-in supplier, call SetSupplierStatus(name, false) instead of deleting it","If credentials must change, overwrite the built-in's config (SaveSupplierConfig) rather than removing it"],"exampleFix":"// before\nfor _, s := range allSuppliers {\n    RemoveSupplier(s) // fails on built-ins\n}\n\n// after\nfor _, s := range allSuppliers {\n    if !public.FileExists(SUPPLIER_TEMPLATE_PATH+\"/\"+s) {\n        RemoveSupplier(s)\n    } else {\n        SetSupplierStatus(s, false) // disable built-ins instead\n    }\n}","handlingStrategy":"validation","validationCode":"func isBuiltinSupplier(name string) bool {\n    return public.FileExists(SUPPLIER_TEMPLATE_PATH + \"/\" + name)\n}\n// only delete customs:\nif !isBuiltinSupplier(name) { RemoveSupplier(name) }","typeGuard":null,"tryCatchPattern":"if err := RemoveSupplier(name); err != nil {\n    if strings.Contains(err.Error(), \"built-in\") {\n        // disable instead: SetSupplierStatus(name, false)\n    } else { return err }\n}","preventionTips":["Filter out names present under SUPPLIER_TEMPLATE_PATH in bulk-delete jobs","Prefer SetSupplierStatus(false) over deletion for built-ins","Never assume every config dir is user-created"],"tags":["configuration","deletion","protected-resource","ai-supplier"],"backgroundTag":"protected-resource-delete","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}