Skip to content

Fix ArgumentError when a host LiveView uses stream/3 by dropping reserved assigns at every field-component spread site#1979

Merged
Flo0807 merged 1 commit into
developfrom
feature/drop-reserved-lv-assigns-in-field-component-spread
May 12, 2026
Merged

Fix ArgumentError when a host LiveView uses stream/3 by dropping reserved assigns at every field-component spread site#1979
Flo0807 merged 1 commit into
developfrom
feature/drop-reserved-lv-assigns-in-field-component-spread

Conversation

@Flo0807
Copy link
Copy Markdown
Collaborator

@Flo0807 Flo0807 commented May 12, 2026

Summary

Backpex spreads the parent LiveView's assigns into child field LiveComponents after dropping a hand-maintained list of keys. That list was missing :streams everywhere, and :uploads / :myself at three of the six sites. When a host LiveView calls stream(socket, :name, []) (or allow_upload/3), the reserved key flows into the child and Phoenix.Component.assign/3 raises:

** (ArgumentError) :streams is a reserved assign by LiveView and it cannot be set directly
    (phoenix_live_view 1.1.30) lib/phoenix_component.ex:1467: Phoenix.Component.validate_assign_key!/1
    (phoenix_live_view 1.1.30) lib/phoenix_component.ex:1405: Phoenix.Component.assign/3
    (stdlib 7.3) maps.erl:894: :maps.fold_1/4
    (backpex 0.18.x) lib/backpex/fields/belongs_to.ex:77: Backpex.Fields.BelongsTo.update/2

This affects every field whose update/2 does socket |> assign(assigns): BelongsTo, HasMany, HasManyThrough, MultiSelect, InlineCRUD.

Changes

  • Add Backpex.HTML.Resource.lv_reserved_assigns/0 returning [:flash, :uploads, :streams, :socket, :myself] — the full set rejected by Phoenix.Component.assign/3 (plus :flash, which was already dropped at every site).
  • Route all six Map.drop(assigns, ...) spread sites through the new helper:
    • lib/backpex/html/resource.ex (3 sites: live_resource_field/1, inlined_resource_field/1, resource_form_field/1)
    • lib/backpex/html/item_action.ex (1 site)
    • lib/backpex/html/resource/resource_form_main.html.heex (1 site)
    • lib/backpex/html/resource/resource_index.html.heex (1 site)
      Site-specific extras (:fields) are prepended with [:fields | lv_reserved_assigns()].
  • Add test/backpex/html/resource_test.exs asserting the helper returns the full reserved set and that dropping it removes :streams from a parent-style assigns map.

No version bump in this PR — will be handled separately when the release is cut.

Test plan

  • mix format
  • mix lint (compile / credo / 95 doctests + 166 tests, 0 failures)
  • mix test test/backpex/html/resource_test.exs — 2/2 pass
  • Demo smoke test in browser: Posts index, Posts /new, Users index, Send-email resource action modal — all render without server or console errors
  • Verify in a consumer app that calls stream/3 on mount and renders a BelongsTo field — page renders without ArgumentError

Backpex spreads the parent LiveView's assigns into child field
LiveComponents after dropping a hand-maintained key list. That list
omitted `:streams` everywhere, and `:uploads` / `:myself` at three of
the six call sites. When a host LiveView called `stream/3` (or
`allow_upload/3`), the reserved key flowed into the child and
`Phoenix.Component.assign/3` raised `ArgumentError` from any field
whose `update/2` does `assign(assigns)` -- `BelongsTo`, `HasMany`,
`HasManyThrough`, `MultiSelect`, `InlineCRUD`.

Centralize the reserved-key set as
`Backpex.HTML.Resource.lv_reserved_assigns/0` and route every spread
site through it. Site-specific extras (`:fields`) are prepended.
@Flo0807 Flo0807 self-assigned this May 12, 2026
@Flo0807 Flo0807 added the bug Something isn't working label May 12, 2026
@Flo0807 Flo0807 requested a review from Copilot May 12, 2026 11:21
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a crash when a host LiveView uses stream/3 (or uploads) by ensuring Backpex never forwards LiveView-reserved assigns (e.g. :streams, :uploads, :myself) when spreading parent assigns into child LiveComponents.

Changes:

  • Centralizes the LiveView-reserved assign keys in Backpex.HTML.Resource.lv_reserved_assigns/0.
  • Updates all documented assign-spread sites to drop the centralized reserved set (plus site-specific keys like :fields).
  • Adds tests verifying the reserved set includes :streams and that dropping it removes :streams from a parent-style assigns map.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
lib/backpex/html/resource.ex Adds lv_reserved_assigns/0 and routes multiple LiveComponent assign spreads through it.
lib/backpex/html/item_action.ex Drops the centralized reserved assigns (plus :fields) when spreading assigns into the modal form component.
lib/backpex/html/resource/resource_index.html.heex Drops reserved assigns (plus :fields) when spreading assigns into the resource-action modal component.
lib/backpex/html/resource/resource_form_main.html.heex Drops reserved assigns when spreading assigns into the main form component.
test/backpex/html/resource_test.exs Adds coverage for the reserved-assign helper and for dropping :streams.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Flo0807 Flo0807 added this pull request to the merge queue May 12, 2026
Merged via the queue into develop with commit 2153343 May 12, 2026
11 checks passed
@Flo0807 Flo0807 deleted the feature/drop-reserved-lv-assigns-in-field-component-spread branch May 12, 2026 11:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants