Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Svelte 5: faulty ownership_invalid_binding errors #11399

Closed
cdcarson opened this issue Apr 30, 2024 · 3 comments · Fixed by #11401
Closed

Svelte 5: faulty ownership_invalid_binding errors #11399

cdcarson opened this issue Apr 30, 2024 · 3 comments · Fixed by #11401
Labels
Milestone

Comments

@cdcarson
Copy link

cdcarson commented Apr 30, 2024

Describe the bug

I'm getting this error...

.../ui/modals/RouteActionModal.svelte passed a value to .../settings/plans/PricingControls.svelte with bind:, but the value is owned by .../plans/[planId]/EditPricingForm.svelte. Consider creating a binding between .../plans/[planId]/EditPricingForm.svelte and .../ui/modals/RouteActionModal.svelte

...when doing something like this...

<script lang="ts">
  // EditPricingForm.svelte
  import RouteActionModal from '$lib/ui/modals/RouteActionModal.svelte';
  import PricingControls from '../PricingControls.svelte';
  type PricingFormData = { serializedPricing: string };
  type PricingFormErrors = { serializedPricing: string|undefined };
  let { notImportant } = $props();
  let data: PricingFormData = $state(/** some initial state base on props **/);
  let errors: PricingFormErrors = $state(/** ditto **/);
</script>

 <RouteActionModal>
    <!-- the problem bindings -->
    <PricingControls bind:data bind:errors />
</RouteActionModal>

So:

  • There are three components
    • RouteActionModal, basically some layout and focus-trapping stuff.
    • EditPricingForm, shown simplified above.
    • PricingControls. This is split out since I use it in other forms.
  • Of those, I'd expect only to see errors for these bindings only if they are wrong as between the latter two components. The modal doesn't know or care about, and should not have to, what I'm passing as it's children.
  • But the warning is about the binding between RouteActionModal and EditPricingForm.

I'm assuming this is a bug. If it's not, I assume the workaround would be to avoid abstracting out PricingControls. That's doable but way less than ideal.

The bindings don't work when you build (i.e. it's not HMR.)

Reproduction

Glad to create a minimal repro, but let me know if it's really a bug first.

Logs

client.js:2639 [svelte] ownership_invalid_binding.../ui/modals/RouteActionModal.svelte passed a value to .../settings/plans/PricingControls.svelte with `bind:`, but the value is owned by .../plans/[planId]/EditPricingForm.svelte. Consider creating a binding between .../plans/[planId]/EditPricingForm.svelte and .../ui/modals/RouteActionModal.svelte
warn @ client.js:2639
ownership_invalid_binding @ warnings.js:55
add_owner @ ownership.js:119
(anonymous) @ EditPricingForm.svelte:37
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
render_effect @ effects.js:222
user_pre_effect @ effects.js:148
(anonymous) @ EditPricingForm.svelte:37
(anonymous) @ snippet.js:27
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
branch @ effects.js:235
(anonymous) @ snippet.js:27
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
block @ effects.js:230
snippet @ snippet.js:18
RouteActionModal @ RouteActionModal.svelte:180
(anonymous) @ hmr.js:34
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
branch @ effects.js:235
(anonymous) @ hmr.js:29
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
block @ effects.js:230
(anonymous) @ hmr.js:20
EditPricingForm @ EditPricingForm.svelte:31
(anonymous) @ hmr.js:34
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
branch @ effects.js:235
(anonymous) @ hmr.js:29
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
block @ effects.js:230
(anonymous) @ hmr.js:20
(anonymous) @ +page.svelte:78
(anonymous) @ if.js:55
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
branch @ effects.js:235
(anonymous) @ if.js:55
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
process_effects @ runtime.js:530
flush_nested_effects @ runtime.js:607
flush_queued_root_effects @ runtime.js:429
process_microtask @ runtime.js:458
client.js:2639 [svelte] ownership_invalid_binding.../ui/modals/RouteActionModal.svelte passed a value to .../settings/plans/PricingControls.svelte with `bind:`, but the value is owned by .../plans/[planId]/EditPricingForm.svelte. Consider creating a binding between .../plans/[planId]/EditPricingForm.svelte and .../ui/modals/RouteActionModal.svelte
warn @ client.js:2639
ownership_invalid_binding @ warnings.js:55
add_owner @ ownership.js:119
(anonymous) @ EditPricingForm.svelte:37
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
render_effect @ effects.js:222
user_pre_effect @ effects.js:148
(anonymous) @ EditPricingForm.svelte:37
(anonymous) @ snippet.js:27
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
branch @ effects.js:235
(anonymous) @ snippet.js:27
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
block @ effects.js:230
snippet @ snippet.js:18
RouteActionModal @ RouteActionModal.svelte:180
(anonymous) @ hmr.js:34
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
branch @ effects.js:235
(anonymous) @ hmr.js:29
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
block @ effects.js:230
(anonymous) @ hmr.js:20
EditPricingForm @ EditPricingForm.svelte:31
(anonymous) @ hmr.js:34
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
branch @ effects.js:235
(anonymous) @ hmr.js:29
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
block @ effects.js:230
(anonymous) @ hmr.js:20
(anonymous) @ +page.svelte:78
(anonymous) @ if.js:55
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
create_effect @ effects.js:98
branch @ effects.js:235
(anonymous) @ if.js:55
execute_reaction_fn @ runtime.js:242
execute_effect @ runtime.js:406
process_effects @ runtime.js:530
flush_nested_effects @ runtime.js:607
flush_queued_root_effects @ runtime.js:429
process_microtask @ runtime.js:458

System Info

System:
    OS: macOS 14.4
    CPU: (8) arm64 Apple M1
    Memory: 170.41 MB / 8.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.12.0 - ~/.nvm/versions/node/v20.12.0/bin/node
    npm: 10.5.0 - ~/.nvm/versions/node/v20.12.0/bin/npm
    pnpm: 9.0.6 - ~/Library/pnpm/pnpm
    bun: 1.0.29 - ~/.bun/bin/bun
  Browsers:
    Chrome: 124.0.6367.93
    Edge: 124.0.2478.67
    Safari: 17.4
  npmPackages:
    svelte: 5.0.0-next.119 => 5.0.0-next.119

Severity

annoyance

@Rich-Harris
Copy link
Member

repro here. it does indeed look like a bug

@Rich-Harris Rich-Harris added this to the 5.0 milestone Apr 30, 2024
Rich-Harris added a commit that referenced this issue Apr 30, 2024
Rich-Harris added a commit that referenced this issue Apr 30, 2024
@cdcarson
Copy link
Author

@Rich-Harris I'm not sure whether this should be a separate issue, but it's related if I get what you all are trying to do with ownership. If I pass state unbound into another component...

<script>
	import SomeForm from './SomeForm.svelte'
	let object = $state({ 
		name: {first: 'Buffy', last: 'Arbuthnot'}, 
		luckyNumbers: [13] 
	});
</script>
<h2>In App</h2>
<pre>{JSON.stringify(object, null, 2)}</pre>
<h2>Form</h2>
<SomeForm {object}/>

...and forget to properly destructure stuff...

<script>
// SomeForm.svelte
	let {object} = $props();
	let data = $state({
                // not properly destructured...
		name: object.name,
                // ditto...
		luckyNumbers: object.luckyNumbers
	});
	const deleteLuckyNumber = (index) => {
		data.luckyNumbers.splice(index, 1)
	}
	const addLuckyNumber = (index) => {
		data.luckyNumbers.push(Math.floor(Math.random() * 1000))
	}
</script>

...then it seems to me that I should get the ownership_invalid_binding error (and it shouldn't work.) I'm modifying state in SomeForm.svelte that doesn't belong to it. I'm not getting any error on the REPL: repro

Sorry if I got the wrong end of the stick.

@Rich-Harris
Copy link
Member

Yep, that looks like another (albeit separate) bug, it should recognise that object.name and object.luckyNumbers belong to object. Hmm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants