makeplane/plane · warning · CommandError
The provided email is already an instance admin.
Error message
The provided email is already an instance admin.
What it means
Raised when `InstanceAdmin.objects.get_or_create(user=user, instance=instance, role=20)` returns `created=False` (lines 35-38), i.e. an `InstanceAdmin` row for that user already exists. IMPORTANT: this raise occurs inside the `try` block (line 30) whose `except Exception` (lines 41-43) catches it, prints it, and re-raises the GENERIC message 'Failed to create the instance admin.' (error 84). So the operator normally never sees this message — they see [84] instead. This masking is a latent bug.
Source
Thrown at apps/api/plane/db/management/commands/create_instance_admin.py:38
def handle(self, *args, **options):
admin_email = options.get("admin_email", False)
if not admin_email:
raise CommandError("Please provide the email of the admin.")
user = User.objects.filter(email=admin_email).first()
if user is None:
raise CommandError("User with the provided email does not exist.")
try:
# Get the instance
instance = Instance.objects.last()
# Get or create an instance admin
_, created = InstanceAdmin.objects.get_or_create(user=user, instance=instance, role=20)
if not created:
raise CommandError("The provided email is already an instance admin.")
self.stdout.write(self.style.SUCCESS("Successfully created the admin"))
except Exception as e:
print(e)
raise CommandError("Failed to create the instance admin.")
View on GitHub (pinned to 1c8a60f858)
Solutions
- Recognize the user is already an admin — no action needed; this is not a real failure.
- To list existing admins: `python manage.py shell -c "from plane.license.models import InstanceAdmin; print([a.user.email for a in InstanceAdmin.objects.all()])"`
- Fix the masking bug by moving the `if not created` check outside the try, or by catching only specific DB exceptions instead of bare `Exception`.
Example fix
# before (bug: [83] is swallowed and re-raised as [84])
try:
_, created = InstanceAdmin.objects.get_or_create(...)
if not created:
raise CommandError("The provided email is already an instance admin.")
except Exception as e:
print(e)
raise CommandError("Failed to create the instance admin.")
# after (move the idempotency check out of the try)
_, created = InstanceAdmin.objects.get_or_create(user=user, instance=instance, role=20)
if not created:
self.stdout.write(self.style.WARNING("Already an instance admin"))
return Defensive patterns
Strategy: try-catch
Validate before calling
from plane.license.models import InstanceAdmin from plane.db.models import User already = InstanceAdmin.objects.filter(user__email='admin@example.com').exists() # if already: skip the command; it is idempotent-but-noisy
Type guard
def is_already_instance_admin(email: str) -> bool:
from plane.license.models import InstanceAdmin
return InstanceAdmin.objects.filter(user__email=email).exists() Try / catch
# WARNING: create_instance_admin masks [83] as [84] via its bare except.
# Pre-check instead of relying on the message:
from plane.license.models import InstanceAdmin
if InstanceAdmin.objects.filter(user__email=email).exists():
print('already an admin; skipping')
else:
call_command('create_instance_admin', email) Prevention
- Pre-check InstanceAdmin membership before running (the command's error is masked).
- Treat 'Failed to create the instance admin' as possibly meaning 'already an admin'.
- Fix the masking bug by moving the idempotency check outside the try.
When it happens
Trigger: Running `create_instance_admin` for a user who is already an instance admin; the get_or_create finds the existing row and `created` is False.
Common situations: Re-running the command after a previous successful run; an admin was provisioned via setup scripts or the UI already.
Related errors
- Failed to create the instance admin.
- User email is required and should have signed in plane
- Please provide the email of the admin.
- User with the provided email does not exist.
- Project ID is required
AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12).
Data as JSON: /api/errors/395e68a1f32db869.
Report an issue: GitHub.