From d636ba4656852b0dfd4745122999a79832948d23 Mon Sep 17 00:00:00 2001 From: Clifford Gama Date: Sun, 27 Apr 2025 22:36:19 +0200 Subject: [PATCH] Raise clear error when non-StreamBlock is passed as top-level block in StreamField (#13068) Fixes #13067 --- CHANGELOG.txt | 1 + docs/releases/7.1.md | 1 + wagtail/fields.py | 7 +++++++ wagtail/tests/test_streamfield.py | 14 ++++++++++++++ 4 files changed, 23 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index f95ff73940..16ed603231 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -24,6 +24,7 @@ Changelog * Preserve query parameters when redirecting from the API `find` view to the `detail` view (Andrew Hosgood) * Add 'Edit' button to success message after copying page (Dhruvi Patel) * Restrict file dialog in multiple image uploader to the allowed image file types (mubarak-mustopha) + * Raise clear error when non-StreamBlock is used as top-level block in StreamField (Clifford Gama) * Fix: Handle lazy translation strings as `preview_value` for `RichTextBlock` (Seb Corbin) * Fix: Fix handling of newline-separated choices in form builder when using non-windows newline characters (Baptiste Mispelon) * Fix: Ensure `WAGTAILADMIN_LOGIN_URL` is respected when logging out of the admin (Antoine Rodriguez, Ramon de Jezus) diff --git a/docs/releases/7.1.md b/docs/releases/7.1.md index c1dd1bdefc..3638334a90 100644 --- a/docs/releases/7.1.md +++ b/docs/releases/7.1.md @@ -36,6 +36,7 @@ The [](settings) app now allows permission over site settings to be granted on a * Preserve query parameters when redirecting from the API `find` view to the `detail` view (Andrew Hosgood) * Add 'Edit' button to success message after copying page (Dhruvi Patel) * Restrict file dialog in multiple image uploader to the allowed image file types (mubarak-mustopha) + * Raise clear error when non-StreamBlock is used as top-level block in StreamField (Clifford Gama) ### Bug fixes diff --git a/wagtail/fields.py b/wagtail/fields.py index cfacc3c258..0db548243c 100644 --- a/wagtail/fields.py +++ b/wagtail/fields.py @@ -146,6 +146,13 @@ class StreamField(models.Field): block = StreamBlock(child_blocks) + if not isinstance(block, StreamBlock): + raise TypeError( + f"The top-level block must be a StreamBlock (got {type(block).__name__}). " + "Either pass a StreamBlock instance/class, or a list of block definitions " + "as (name, block) tuples." + ) + block.set_meta_options(self.block_opts) return block diff --git a/wagtail/tests/test_streamfield.py b/wagtail/tests/test_streamfield.py index 93a1294eae..1cfb74dc79 100644 --- a/wagtail/tests/test_streamfield.py +++ b/wagtail/tests/test_streamfield.py @@ -1200,3 +1200,17 @@ class TestDeconstructStreamFieldWithLookup(TestCase): }, }, ) + + +class TestBlockTypeValidation(TestCase): + def test_non_streamblock_raises_correct_error(self): + """stream_block raises useful error message when non-StreamBlock is provided.""" + msg = ( + "The top-level block must be a StreamBlock (got StructBlock). " + "Either pass a StreamBlock instance/class, or a list of block definitions " + "as (name, block) tuples." + ) + + with self.assertRaisesMessage(TypeError, msg): + field = StreamField(blocks.StructBlock([("name", blocks.CharBlock())])) + field.stream_block