openedx / openedx/xblocks-core
Poll XBlock: no Studio editing view, and empty Poll blocks are permanently unloadable in Content Libraries v2
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 15
- Avg merge
- 5d 16m
- Merged PRs (30d)
- 7
Description
Which "Poll" block is this about?
There are two unrelated XBlocks that both show up as "Poll" in Open edX, and this issue is about the second one:
| Category | Package | Affected by this issue? | |
|---|---|---|---|
| Poll | poll |
third-party xblock-poll (OpenCraft/eduNEXT) |
No — separate codebase, not touched here |
| Poll Question | poll_question |
xblocks_contrib.poll.PollBlock, this repo |
Yes — this issue |
poll (xblock-poll) is in Studio's DEFAULT_ADVANCED_MODULES, so it's the one that shows up automatically in the "Add Component → Advanced" menu with a friendly editor — it is not affected by anything below. poll_question is the legacy block being extracted/maintained in xblocks_contrib.poll, is not in the default advanced module list, and is the subject of both bugs described here.
Summary
xblocks_contrib.poll.PollBlock (i.e. poll_question, not the unrelated poll/xblock-poll block — see above) has no Studio editing view — it defines only student_view. Confirmed by reading poll.py and its mixins (LegacyXmlMixin): no studio_view, no StudioEditableXBlockMixin, nothing renders an editor.
Reproduced live: in a sandbox with poll_question added to Advanced Module List, clicking "Edit" on a Poll block in the Studio unit page fails — edit_xblock.js errors with xblockElement is empty or not defined because the /action/edit endpoint has no view to render.
To rule out a wiring bug rather than a genuine gap, compared Poll against every other extracted block pairing LegacyXmlMixin with a plain XBlock:
| Block | studio_view |
Dedicated editor template/JS/CSS |
|---|---|---|
| Video | ✅ | ✅ |
| Annotatable | ✅ | ✅ (annotatable_editor.html/js/css) |
| Word Cloud | ✅ | ✅ |
| HTML | ✅ | ✅ |
| LTI | ✅ | ✅ |
| Discussion | ✅ | ✅ |
| Poll | ❌ | ❌ — no poll_editor.* files exist at all |
Every sibling block shipped a matching studio_view + editor assets during extraction. Poll's directory only has the student-view assets (poll.html/poll.css/poll.js) — no editor files were ever added. Its 2-test suite (test_poll_block_construction, test_vote_success) doesn't touch editing either. This looks like the editor was simply never built for Poll, not a regression.
Why this matters now
Found while reviewing openedx/openedx-platform#38744 (slash-n-burn removal of the built-in Poll block). The built-in _BuiltInPollBlock had a working editor via legacy XModuleMixin/XModuleToXBlockMixin machinery (auto-generated metadata/raw-XML editor for XModule-style descriptors). That machinery was correctly not carried over during extraction — the new block is a plain XBlock — but no replacement editing view was ever added.
Since USE_EXTRACTED_POLL_QUESTION_BLOCK has defaulted to True since December, this gap has been live but masked: operators could always set the toggle back to False to get a working editor. openedx-platform#38744 removes that fallback entirely, which would make poll_question permanently uneditable in Studio for any existing course content.
Second, independent bug: an empty Poll block is permanently unloadable in Content Libraries v2
While investigating a workaround for the missing editor above (author via raw OLX instead), found a second, more severe bug specific to the Learning Core runtime (Content Libraries v2).
Root cause: PollBlock.definition_from_xml() (poll.py:449) hard-fails with ValueError if the block's OLX has zero <answer> tags. In a legacy Modulestore course, this only runs once, at XML import time — once a block is successfully imported, its fields are read directly from the document store on every subsequent load, never re-validated. But the Learning Core runtime backing Content Libraries v2 stores content as OLX and calls parse_xml() → definition_from_xml() on every single load (learning_core_runtime.py:219). Since blocks are always created empty (no answers) via the standard creation API — exactly what Studio's "Add Component" flow does — a Poll block becomes permanently unloadable from the moment it's created, including for the purpose of ever adding answers to it. Every fields-fetch, render, or embed request 500s, forever.
Reproduction (confirmed directly, not just by code reading)
Reproduced in a local Tutor devstack using the real xblocks_contrib.poll.PollBlock class via openedx.core.djangoapps.content_libraries.api and openedx.core.djangoapps.xblock.api:
File ".../openedx/core/djangoapps/xblock/runtime/learning_core_runtime.py", line 219, in get_block
block = block_class.parse_xml(xml_node, runtime=self, keys=keys)
File ".../xblocks_contrib/poll/poll.py", line 596, in parse_xml
definition, children = cls.load_definition(definition_xml, runtime, keys.def_id, runtime.id_generator)
File ".../xblocks_contrib/poll/poll.py", line 532, in load_definition
definition, children = cls.definition_from_xml(definition_xml, system)
File ".../xblocks_contrib/poll/poll.py", line 449, in definition_from_xml
raise ValueError(
ValueError: Poll_question definition must include at least one 'answer' tag
Controlled comparison, same block class, same library, only difference is whether <answer> tags exist in the OLX at creation time:
- Block created empty (via
create_library_block, matching the "Add Component" flow) →load_block()throws theValueErrorabove on every subsequent call. Confirmed 3 times. - Same block type, OLX set to include real
<answer>tags viaset_library_block_olx()before any load →load_block()andrender_block_view('student_view')both succeed cleanly.
Also confirmed neither Word Cloud's nor Annotatable's definition_from_xml has an equivalent hard-fail-on-empty check, so they don't hit this — it's Poll-specific.
This matches the empty <poll_question/> OLX found in an openedx-platform course export after adding a Poll via Studio's "Add Component" (see openedx-platform#38744 for that trail) — consistent with real blocks getting stuck in this state as soon as they're created, before anyone has a chance to add answers.
Practical implication: a Poll block copy-pasted from an already-populated course unit (carrying real <answer> tags in its OLX) should survive being loaded in a library. But any Poll created directly in a library (once/if poll_question is ever added to LIBRARY_ENABLED_BLOCKS) would be born broken.
Proposed fix
- Add a
studio_viewtoPollBlock, most likely viaxblock.utils.studio_editable.StudioEditableXBlockMixin(the same pattern already used by other extracted blocks like Word Cloud) covering the editable fields:display_name,question,answers. - Make
definition_from_xmltolerate zero answers (e.g. default toanswers=[]with a warning instead of raising), so a freshly-created block is loadable and editable rather than being permanently bricked. The strict validation may still make sense as an import-time-only check (e.g. moved to a course-import validation step) rather than something enforced on every load.
Blocks
- openedx/openedx-platform#38744 should not merge until both of these are resolved.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with xblocks_contrib/poll/poll.py, especially PollBlock.definition_from_xml(), its parsing path, and the existing poll tests. Then trace openedx-platform's learning_core_runtime.py get_block() behavior and compare the extracted blocks' Studio editing patterns. Done means empty Poll blocks load successfully in Content Libraries and Poll has a working Studio editing view, with regression coverage for both paths.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100