Skip to content

Form submissions return 404 with Wagtail 7.x due to FormMixin isinstance check #710

Description

@rosslaird

As @vsalvino and the team know, I am not a programmer and tend to find my way by trial and error (mostly error). So, like many people lately, I've been using Claude Code to assist with web development. The error description below was created by Claude in response to an error I am seeing. I apologize if it's inappropriate to post an issue generated by an LLM (it does look like a pretty good issue description, though...).

Description

Form submissions are inaccessible in the Wagtail admin (404 error) when using CodeRed CMS 6.0 with Wagtail 7.x. The Forms listing page shows forms correctly, but clicking to view submissions returns a 404.

Steps to Reproduce

  1. Install CodeRed CMS 6.0.0 with Wagtail 7.1.x
  2. Create a FormPage with some form fields
  3. Submit the form a few times to create submissions
  4. Go to Wagtail admin → Forms
  5. Click on the form page to view submissions
  6. Result: 404 error at /admin/forms/submissions/<page_id>/

Root Cause

In May 2025, Wagtail added an isinstance check in wagtail/contrib/forms/views.py (commit efd5d49):

def get_submissions_list_view(request, *args, **kwargs):
    page_id = kwargs.get("page_id")
    form_page = get_object_or_404(Page, id=page_id).specific
    if not isinstance(form_page, FormMixin):
        raise Http404  # <-- This causes the 404
    return form_page.serve_submissions_list_view(request, *args, **kwargs)

The problem is that CoderedFormMixin does not inherit from wagtail.contrib.forms.models.FormMixin:

>>> from wagtail.contrib.forms.models import FormMixin
>>> from coderedcms.models import CoderedFormPage, CoderedFormMixin
>>> issubclass(CoderedFormPage, FormMixin)
False
>>> issubclass(CoderedFormMixin, FormMixin)
False

Suggested Fix

CoderedFormMixin should inherit from wagtail.contrib.forms.models.FormMixin to pass the isinstance check. This may require reconciling any method/attribute conflicts between the two mixins.

Alternatively, CodeRed CMS could register its own URL route for form submissions that bypasses Wagtail's check.

Environment

  • CodeRed CMS: 6.0.0
  • Wagtail: 7.1.1
  • Python: 3.14
  • Django: 5.1.x

Related

This likely also affects wagtail-flexible-forms since StreamFormMixin similarly does not inherit from Wagtail's FormMixin.

Activity

  1. rosslaird commented on Jan 26, 2026

    @rosslaird
    ContributorAuthor

    I think this is the first issue for the repo in which the use of AI in finding and creating the issue was specifically disclosed. I see that Ghostty has recently developed an AI use policy for contributions, which looks reasonable and useful. In the absence of anything similar for CodeRed, I have reviewed that document and ensured that my issue complies with those guidelines (since they are very broad and are intended to apply to situations like this).

    Moving forward, it seems pretty clear that AI-assisted coding is going to be (already is) the norm, so more of the issues and pull requests here will reflect that reality.

  2. harlanji commented on Mar 5, 2026

    @harlanji

    I ran into this and worked around by using the dbshell: python manage.py dbshell and then querying the table: select * from wagtailforms_formsubmission;.

    I hope a fix is forthcoming. Thanks.

  3. bradrice commented on May 6, 2026

    @bradrice

    I too am having this issue.

  4. bradrice commented on Jul 17, 2026

    @bradrice

    I've opened a PR that fixes this: #717.

    Root cause is as described above — Wagtail 7.x guards its admin submissions view with isinstance(page, FormMixin) and now calls page.get_submissions(), which CodeRed form pages didn't satisfy.

    The fix has CoderedFormPage and CoderedStreamFormPage inherit Wagtail's FormMixin as the last base. FormMixin is a fieldless plain mixin, so there's no migration, and putting it last means it only supplies the missing get_submissions() / get_submissions_list_view_class() and satisfies the isinstance check without shadowing any existing methods.

    One thing worth noting for reviewers: adding FormMixin to the shared CoderedFormMixin instead breaks advanced (StreamField) forms — it lands ahead of wagtail_flexible_forms.StreamFormMixin in the MRO and hijacks get_form_fields() ('StreamValue' object has no attribute 'all'). Inheriting on the two page classes, last, fixes both standard and advanced forms.

    Includes a regression test covering the admin forms index and the submissions view for both form types (they fail without the fix), plus release notes. Full suite passes (72), ruff/codespell clean, no migration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions