django/django · warning · Http404

Content type %(ct_id)s object %(obj_id)s doesn’t exist

Error message

Content type %(ct_id)s object %(obj_id)s doesn’t exist

What it means

Raised as Http404 by contenttypes shortcut() when looking up either the ContentType or the target object raises ObjectDoesNotExist, or when object_id cannot be parsed (ValueError), or fails validation (ValidationError). It signals that the (content_type_id, object_id) pair does not resolve to a real object.

Source

Thrown at django/contrib/contenttypes/views.py:23

from django.http import Http404, HttpResponseRedirect
from django.utils.translation import gettext as _


def shortcut(request, content_type_id, object_id):
    """
    Redirect to an object's page based on a content-type ID and an object ID.
    """
    # Look up the object, making sure it's got a get_absolute_url() function.
    try:
        content_type = ContentType.objects.get(pk=content_type_id)
        if not content_type.model_class():
            raise Http404(
                _("Content type %(ct_id)s object has no associated model")
                % {"ct_id": content_type_id}
            )
        obj = content_type.get_object_for_this_type(pk=object_id)
    except (ObjectDoesNotExist, ValueError, ValidationError):
        raise Http404(
            _("Content type %(ct_id)s object %(obj_id)s doesn’t exist")
            % {"ct_id": content_type_id, "obj_id": object_id}
        )

    try:
        get_absolute_url = obj.get_absolute_url
    except AttributeError:
        raise Http404(
            _("%(ct_name)s objects don’t have a get_absolute_url() method")
            % {"ct_name": content_type.name}
        )
    absurl = get_absolute_url()

    # Try to figure out the object's domain, so we can do a cross-site redirect
    # if necessary.

    # If the object actually defines a domain, we're done.
    if absurl.startswith(("http://", "https://", "//")):

View on GitHub (pinned to ae25a40be0)

Solutions

  1. Verify the object exists before emitting the shortcut URL in templates (use get_absolute_url only on real instances).
  2. Handle 404s in the frontend by re-fetching or hiding broken links.
  3. Ensure object_id values are valid integer pks (or match the model's pk type) before link generation.
  4. Run remove_stale_contenttypes if ContentType IDs are drifting.

Example fix

// before (template emits link to maybe-deleted object):
<a href="/r/{{ ct.id }}/{{ obj.id }}/">view</a>

// after (guard before rendering):
{% if obj %}<a href="{{ obj.get_absolute_url }}">view</a>{% endif %}
Defensive patterns

Strategy: validation

Validate before calling

from django.contrib.contenttypes.models import ContentType

def resolve_or_none(ct_id, obj_id):
    try:
        ct = ContentType.objects.get(pk=ct_id)
        if not ct.model_class():
            return None
        return ct.get_object_for_this_type(pk=obj_id)
    except (ContentType.DoesNotExist, ValueError, Exception):
        return None

obj = resolve_or_none(content_type_id, object_id)
if obj is None:
    # render a graceful 'not found' instead of relying on Http404
    ...

Try / catch

from django.http import Http404
try:
    obj = ct.get_object_for_this_type(pk=object_id)
except (ObjectDoesNotExist, ValueError, ValidationError):
    raise Http404('Resource not found')

Prevention

When it happens

Trigger: A request to /r/<ct_id>/<obj_id>/ where ct_id has no ContentType, obj_id has no matching object, obj_id is non-numeric (ValueError on int pk), or a custom pk field fails ValidationError.

Common situations: Stale links/breadcrumbs/bookmarks pointing at deleted objects; templates rendering links before objects exist; user-tampered URLs with arbitrary IDs.

Related errors


AI-assisted analysis of django/django@ae25a40be0 (2026-08-06). Data as JSON: /api/errors/f4f755f8abee5984. Report an issue: GitHub.