{"record":{"id":"ec4d605b42be4329","repo":"invoke-ai/InvokeAI","slug":"only-admins-can-create-default-presets","errorCode":null,"errorMessage":"Only admins can create default presets","messagePattern":"Only admins can create default presets","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"invokeai/app/api/routers/style_presets.py","lineNumber":212,"sourceCode":") -> StylePresetRecordWithImage:\n    \"\"\"Creates a style preset\"\"\"\n\n    try:\n        parsed_data = json.loads(data)\n        validated_data = StylePresetFormData(**parsed_data)\n\n        name = validated_data.name\n        type = validated_data.type\n        positive_prompt = validated_data.positive_prompt\n        negative_prompt = validated_data.negative_prompt\n        is_public = validated_data.is_public\n\n    except (json.JSONDecodeError, pydantic.ValidationError):\n        raise HTTPException(status_code=400, detail=\"Invalid preset data\")\n\n    # Only admins may create default-typed presets — they're the shipped catalog.\n    if type == PresetType.Default and not current_user.is_admin:\n        raise HTTPException(status_code=403, detail=\"Only admins can create default presets\")\n\n    pil_image = None\n    if image is not None:\n        if not image.content_type or not image.content_type.startswith(\"image\"):\n            raise HTTPException(status_code=415, detail=\"Not an image\")\n\n        contents = await image.read()\n        try:\n            pil_image = await asyncio.to_thread(Image.open, io.BytesIO(contents))\n\n        except Exception:\n            ApiDependencies.invoker.services.logger.error(traceback.format_exc())\n            raise HTTPException(status_code=415, detail=\"Failed to read image\")\n\n    preset_data = PresetData(positive_prompt=positive_prompt, negative_prompt=negative_prompt)\n    style_preset = StylePresetWithoutId(name=name, preset_data=preset_data, type=type, is_public=is_public)\n    new_style_preset = await asyncio.to_thread(\n        ApiDependencies.invoker.services.style_preset_records.create,","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/api/routers/style_presets.py#L194-L230","documentation":"After validating the form data, create_style_preset rejects non-admin users who attempt to create a preset with type PresetType.Default, returning HTTP 403 'Only admins can create default presets'. Default presets are the shipped catalog and are admin-managed by design.","triggerScenarios":"POST /style_presets/ with data JSON containing \"type\": \"default\" (PresetType.Default) while the authenticated user's is_admin is false.","commonSituations":"Client UI defaulting the type dropdown to 'default'; copying a shipped default preset's JSON as a template and forgetting to change its type; non-admin service accounts automating imports; user account lacking admin role after an instance migration.","solutions":["Change the preset type in the data payload to 'user' (or another non-default PresetType).","If a default preset is genuinely needed, have an admin account create it, or ask an admin to grant the account admin rights.","Fix the client UI so new presets default to type 'user'.","When duplicating a default preset, strip/replace the type field before POSTing."],"exampleFix":"// before\nconst preset = { ...copiedDefault, name: \"Mine\" }; // type: \"default\"\n\n// after\nconst preset = { ...copiedDefault, name: \"Mine\", type: \"user\" };","handlingStrategy":"validation","validationCode":"function assertCanCreateType(presetType, currentUser) {\n  if (presetType === \"default\" && !currentUser.is_admin) {\n    throw new Error(\"Only admins can create default presets\");\n  }\n}\n\nassertCanCreateType(preset.type, currentUser); // before POST /style_presets/","typeGuard":"function isAdminUser(u: { is_admin?: boolean }): u is { is_admin: true } {\n  return u.is_admin === true;\n}","tryCatchPattern":"try {\n  return await api.createStylePreset({ data: JSON.stringify(preset), image });\n} catch (e) {\n  if (e.status === 403 && e.detail === \"Only admins can create default presets\") {\n    // non-admin: coerce to 'user' type or prompt for admin elevation\n    return api.createStylePreset({ data: JSON.stringify({ ...preset, type: \"user\" }), image });\n  } else throw e;\n}","preventionTips":["Never send type 'default' unless the account is verified admin.","Hide/lock the default-type option for non-admin users in the UI.","When cloning a shipped preset, always rewrite type to 'user'.","Check the current user's role from the API before offering admin-only operations."],"tags":["http-403","authorization","permissions","multiuser"],"backgroundTag":"insufficient-permissions","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}