HumanSignal/label-studio · error · KeyError

Can't find Project by invite URL: {url}

Error message

Can't find Project by invite URL: {url}

What it means

Project.find_by_invite_url extracts the last path segment of an invite URL as a token; it raises KeyError only when the token is empty (URL has no trailing segment). A non-empty but unknown token will instead raise Project.DoesNotExist from .get().

Source

Thrown at label_studio/projects/models.py:473

        if self.tasks.count() == 0:
            return 0
        return self.tasks.aggregate(Sum('overlap'))['overlap__sum']

    @property
    def get_available_for_labeling(self):
        return self.get_collected_count - self.get_labeled_count

    @property
    def need_annotators(self):
        return self.maximum_annotations - self.num_annotators

    @classmethod
    def find_by_invite_url(cls, url):
        token = url.strip('/').split('/')[-1]
        if len(token):
            return Project.objects.get(token=token)
        else:
            raise KeyError(f"Can't find Project by invite URL: {url}")

    def reset_token(self):
        self.token = create_hash()
        self.save(update_fields=['token'])

    def add_collaborator(self, user):
        created = False
        with transaction.atomic():
            try:
                ProjectMember.objects.get(user=user, project=self)
            except ProjectMember.DoesNotExist:
                ProjectMember.objects.create(user=user, project=self)
                created = True
            else:
                logger.debug(f'Project membership {self} for user {user} already exists')
        return created

    def has_collaborator(self, user):

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Ensure the invite URL ends with the project's token
  2. Regenerate the link via the project's reset_token / invite UI
  3. Check Project.token is non-empty in the DB
  4. Catch Project.DoesNotExist separately — the message shown would differ

Example fix

# before
project = Project.find_by_invite_url(invite_url)
# after
if not invite_url or not invite_url.strip('/').split('/')[-1]:
    raise ValueError('Invite URL missing project token')
project = Project.find_by_invite_url(invite_url)
Defensive patterns

Strategy: validation

Validate before calling

token = url.strip('/').split('/')[-1] if url else ''
if not token:
    raise ValueError('invite URL missing project token')

Try / catch

try:
    project = Project.find_by_invite_url(url)
except KeyError:
    ...  # empty token — fix link
except Project.DoesNotExist:
    ...  # unknown/expired token — regenerate link

Prevention

When it happens

Trigger: Calling Project.find_by_invite_url with '', a URL like 'https://host/p/invite' with nothing after the last '/', or a URL whose token was stripped before this call.

Common situations: Blank invite-link env/settings; copying base link without token; client trimming the URL; template rendering the token as empty because project.token was never generated (call reset_token()).

Related errors


AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29). Data as JSON: /api/errors/e74bee202f848882. Report an issue: GitHub.