Skip to content

Unhelpful error on property access on reactive variable that's undefined #14389

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

Open
joakim opened this issue Nov 21, 2024 · 3 comments
Open

Comments

@joakim
Copy link
Contributor

joakim commented Nov 21, 2024

Describe the bug

Svelte 5 produces an unhelpful error if:

  1. A reactive variable is assigned an object whose properties are referenced in markup
  2. The reactive variable gets reassigned to undefined

Uncaught TypeError: get(...) is undefined

This obscures what caused the error. A more helpful error message would be, similar to WebKit's:

Uncaught TypeError: undefined is not an object (evaluating 'foo.bar')

It can be caused by a function that usually returns an object, but may possibly return undefined, a common pattern in JS. This is the kind of bug that only happens in edge cases, making it hard to catch and reproduce.

In TypeScript, you do get a … is possibly 'undefined' error in the editor when referencing the property, and using the optional chaining operator ?. and nullish coalescing operator ?? prevents the error. Not all developers or libraries use TypeScript though, and one may have used type assertion, stopping TypeScript from detecting the type error.

In any case, informative error messages prevent headaches.

Related issue: #13619

(Thanks for your hard work on Svelte!)

Reproduction

Logs

Uncaught TypeError: get(...) is undefined
    App playground:output:2870
    update_reaction playground:output:1791
    update_effect playground:output:1917
    process_effects playground:output:2092
    flush_queued_root_effects playground:output:1984
    process_deferred playground:output:2031
    schedule_effect playground:output:2048
    mark_reactions playground:output:413
    internal_set playground:output:334
    set playground:output:320
    on_click playground:output:2854
    handle_event_propagation playground:output:2512

System Info

N/A

Severity

annoyance

@Conduitry
Copy link
Member

Conduitry commented Nov 21, 2024

This error is coming directly from the JS engine, and so is going to vary across Chrome / Firefox / WebKit. Attempting to catch this, detect the specific version of if that's unhelpful, and re-throwing an error with a different message sounds like a bad idea. Adding special handling for foo.bar that first checks whether foo is undefined and throws a separate error early (before getting to the error that would be thrown by the browser) also sounds messy and also sounds like a bad idea.

@joakim
Copy link
Contributor Author

joakim commented Nov 21, 2024

I see. I suppose it's unlikely to occur if people use TypeScript and best practices, which is the case for most professional projects. That includes never trusting the output of untyped library functions, being careful with type assertions and using optional chaining and nullish coalescing when necessary.

I'm OK with closing this and leaving it as a reference for future searches on the error message.

Here's how it varies by browser (adopted from MDN):

TypeError: get(...) is not an object (Firefox)
TypeError: undefined is not an object (evaluating 'get(x).y') (Safari)
TypeError: Cannot read properties of undefined (reading 'x') (Chrome/V8-based)

The error message in my bug report was from Firefox.

Interesting: In Safari, the Playground's console only shows a null error message, but a nice and informative error message in the Web Inspector's console (TypeError: undefined is not an object (evaluating 'get(foo).bar')). Is that a bug in the playground?

@lexszero
Copy link

lexszero commented May 3, 2025

I've ran into similar problem, though in my case it seems less straightforward than just using undefined.

I have a $derived state variable that could be either an object or undefined (which is a legit value in my case). The block where it's accessed is explicitly wrapped in {#if ..} to conditionally render the contents only when it is defined, but that doesn't help, and the crashes seem to be opportunistic: sometimes it fails, sometimes it doesn't. This state could change very rapidly, as it is triggered by mouseover events when the user is hovering over many small elements, and this derived state variable represents which one is currently under cursor, if any. It worked great until I did some refactoring that should not significantly change the logic, and I've been banging my head on it for hours to no avail.

It appears that there is some sort of race condition happening when components are being destroyed when the state variable becomes undefined, but the destruction code still tries to go through reactive getters. Adding $state.snapshot() in different places also doesn't help.

I wasn't able to reproduce it with a minimal synthetic example, everything I came up with works as expected, so here's the most relevant part of the breaking change in my working codebase (MapContent.svelte:164-200)

I would appreciate if someone more experience with Svelte could take a look at it, maybe I'm just doing something very stupid.

And this is how it looks in console with $inspect on variable in question (this is Firefox, it behaves the same in Chrome) - notice that exactly every other Object -> undefined change is causing an error - it would be less weird if it was failing every time.

Image

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

No branches or pull requests

3 participants