# Possible bug: Empty plain objects pick up a toString key when referenced in the view (until a key is added to them)

**URL:** <https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583>\
**Category:** Framework Knowledge\
**Created:** [January 24, 2026, 4:39am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583 "2026-01-24T04:39:51Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [January 24, 2026, 4:39am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/1 "2026-01-24T04:39:51Z")

</div>

Hello,

I’m not sure if this is bug, or something happened to my environment (maybe Object was patched somewhere, though I can’t find such a patching), or maybe I’m just losing my mind.

When I initialize a class member, for example, like this:

```javascript
this.someObject = {}

```

and then reference it in a get, like this:

```javascript
get hasIssues() {
   return !!Object.keys(this.someObject).length;
}

```

it shows up like this the first time it’s accessed as, say, `if.bind="model.hasIssues"` in the view (hovering over it at a breakpoint in `hasIssues()` ):

 ![image](https://canada1.discourse-cdn.com/flex027/uploads/aurelia/original/2X/2/224950cb0a7de076c3b390fa2dae634ad03ba3fb.png)

The problem is that `toString` is seen as a key such that `Object.keys(…).length` returns a length of 1.

**Is this intended?** I don’t remember having this problem before installing Au 2.0 RC as it would have broken quite a bit of code. I’m not sure. `toString` is not there as a key once I add a key to it (it’s on the prototype).

I think it has to do with your handling of proxies.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [January 24, 2026, 5:06am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/2 "2026-01-24T05:06:55Z")

</div>

Its a bug, the exclusion prop list need to be more extensive. Though itll take a few goes. Thanks @estaylorco

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [January 24, 2026, 5:09am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/3 "2026-01-24T05:09:47Z")

</div>

Whew! I thought I was losing my mind!

This is what I did as a workaround (for others who are experiencing this):

```javascript
get issuesAsList() {
  return Object.values(JSON.parse(JSON.stringify(this.someObject)));
}

```

Glad to see you resurface @bigopon ! I know you’ve been very busy with the router (I subscribe to GitHub notifications)…and with stabilizing RC.

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [January 26, 2026, 1:46am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/4 "2026-01-26T01:46:06Z")

</div>

Hello @bigopon ,

I just noticed that `toJSON` also winds up on an empty object, like `toString`. I use `toJSON` to customize the JSON that’s produced by my models.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [January 31, 2026, 11:14am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/5 "2026-01-31T11:14:03Z")

</div>

@estaylorco how did you get `toString` tracked? In my test it isn’t touched with in `Object.keys`call.

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [January 31, 2026, 4:55pm UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/6 "2026-01-31T16:55:26Z")

</div>

Hello @bigopon . I’ll need to explore this further. I was perplexed in the first place myself. `toJSON` I understand because it’s on the base class of all of my models…and I wrote it.

I have `toString` in three places, two of which are inside methods I don’t even call anywhere in my migration test target

The only place that `toString` could bubble into the view or the viewModel is in this value converter:

**cssLength.js**

```javascript
import { valueConverter } from 'aurelia';

@valueConverter('cssLength')
export class CssLength {
  toView(numberOrString, uom = 'px') {
    return toCssLength(numberOrString, uom);
  }
}

export function toCssLength(numberOrString, uom = 'px') {
  let length;

  if (typeof numberOrString === 'string') {
    length = numberOrString + (parseInt(numberOrString, 10).toString() === numberOrString ? uom : '');
  } else if (typeof numberOrString === 'number') {
    length = numberOrString.toString(10) + uom;
  }

  return length;
}

```

I’ll work on it today. Any ideas what I could be doing myself to cause this?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [January 31, 2026, 8:30pm UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/7 "2026-01-31T20:30:36Z")

</div>

the code you post above doesn’t seem to be causing it, so probably we will have to look at somewhere else. Or maybe assign a new `toString` fn to the object and return some lengthy string to see where it’s being used?

```auto
object.toString = () => '-'.repeat(1e5)

```

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [January 31, 2026, 10:31pm UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/8 "2026-01-31T22:31:31Z")

</div>

Continuing to explore this…

The problem I’m facing is that `toString` doesn’t always track. I haven’t even figured out where’s that’s originating, or when for that matter. If I do as you suggest, I would be manually creating the problem we’re trying solve…I think.

So, I turned my attention to other method that’s getting tracked: `toJSON`.

Before I explore further, `toJSON` is on my model base class, `TsiModelBase`. I’m convinced I’m not doing anything wrong, but I do believe I’m doing something different from what most are doing. A problem like this would case any testing of `length` on `Object.keys(…)` to fail. That would have hit the news by now.

I wonder if it’s the fact that I return a `Proxy` out of `TsiModelBase`. This is what I do in my Au 1.0 app to support change detection. Three hashes—current, previous, and original—control detecting changes during editing of a model, and auto-saving. Allow me to supply the entire code path:

**TsiModelBase.js**

```javascript
import hashing from 'jshashes';
import {isEmpty as __isEmpty, pick as__ pick} from 'lodash-es';
...
constructor() {
   ...
   this.hasher = new hashing.SHA1().b64;
   return new Proxy(this, this._proxyHandler()); // <-- Last line of ctor   
}

  
_proxyHandler() {
  return {
    set: function (obj, prop, newValue) {
      obj[prop] = newValue;

      if (!obj._suspendHashing && Object.hasOwn(obj, prop)) {
        obj._handleProxiedSet(obj, prop, newValue);
      }

      return true;
    },
  };
}

_handleProxiedSet(obj, prop, newValue) {
  obj._updateHashes.call(obj);
}

_updateHashes() {
  if (!this.hashes || __isEmpty(this.hashes)) return;

  const h = this.hashes;

  h.previousHash = h.currentHash;
  h.currentHash = this._computeHash();
}

_computeHash(o = this) {  
  return this.hasher(JSON.stringify(o)); // <-- This is where toJSON() would be accessed and possibly tracked
}

toJSON() {
  return __pick(this, Object.keys(this.defaults()));
}

defaults() {
  return {...} // <-- An object with default properties and values that represent the "data" of the object for change detection purposes
}

```

Could proxying what I now realize is already a proxy be causing this problem? You weren’t using proxies in Au 1.0.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [January 31, 2026, 10:59pm UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/9 "2026-01-31T22:59:03Z")

</div>

it’s hard to say. And you’ll probably have to add a few more logs here and there.

Regardless, back to our original issue where `toString` is being tracked, on a 2nd thought, I don’t think we can just change this behavior, since there’s no way to tell whether it’s intentional or not from the framework perspective. Same for `toJSON`. Maybe you can do something like this

```auto
import { ProxyObservable } from 'aurelia'

get myGetter() {
  raw = ProxyObservable.getRaw(this); // opt-out tracking
  ...
}

```

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [January 31, 2026, 11:28pm UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/10 "2026-01-31T23:28:40Z")

</div>

What behavior would you be changing? For `toString` and `toJSON` to become tracked when they’re both functions, such that they because keys on the object, that’s certainly nothing I’m doing intentionally. I wouldn’t even know how to do that without just setting a property.

This is causing `Object.keys(…).length` to return surprises all over the place.

In any case, I’ll continue to explore, of course.

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [February 1, 2026, 2:08am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/11 "2026-02-01T02:08:59Z")

</div>

@bigopon I believe I have some information that will help us track this down!

I think I was right to track down `toJSON` first, with the assumption that in uncovering the issue there, we might have a clue as to what’s going on with `toString` as well.

First, a few points:

- I commented out the only instance of `toJSON` in my migration test target. This method is on `TsiModelBase` and is inherited by all models (in my migration test target, however, I have only one model).
- I commented out the return of a `Proxy` out of `TsiModelBase`, which didn’t solve the problem. So we can rule out a proxy on a proxy as the root cause.
- My preliminary conclusion is that it is not _my_ `toJSON` that winds up tracked on the validation object (which is initialized as `{}` on `TsiModelBase`).

**The following code is the culprit** (I can comment _out_ and comment back _in_ to eliminate the tracked `toJSON` artifact, and produce it, respectively):

**TsiModelBase.js**

```javascript
...

@computed((model) => model.validation, { deep: true })
get hasValidationErrors() {
  return Object.keys(JSON.parse(JSON.stringify(this.validation)))?.some((_prop) => !this.validation[_prop].isValid);
}

...

```

Now, **it’s not the entirety of this code** that’s causing the problem. It is specifically this:

```javascript
JSON.parse(JSON.stringify(this.validation))

```

so that if I eliminate it, and go with this:

```javascript
...

@computed((model) => model.validation, { deep: true })
get hasValidationErrors() {
  return Object.keys(this.validation)?.some((_prop) => !this.validation[_prop].isValid);
}

...

```

the problem goes away. **There is no tracked `toJSON` artifact on the validation object.**

So what is it about `JSON.parse/JSON.stringify` that’s causing the framework to track a `toJSON` artifact?

#### So what does this have to do with `toString`?

I introduced `JSON.parse/JSON.stringify` to eliminate the tracked `toString` artifact, which it did. But that caused the tracked `toJSON` artifact to appear.

I have a feeling that the root cause for _both_ stray tracked artifacts is the same.

Does this help?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [February 7, 2026, 5:12am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/12 "2026-02-07T05:12:28Z")

</div>

`toJSON` is a standard feature of `JSON.stringify`. When you do:

```auto
JSON.stringify({ a: 1, toJSON() { return { a: 2 } })

```

you get `"{ “a”: 2 }”` instead of `"{ “a”: 1 }”`. Because of that, calling JSON.stringify on an object will get `toJSON` tracked, I don’t know if there’s any safe assumption around this.

For `toString`, it’s probably something somewhere else, easiest to detect is you assign/override a `toString()` method on the object you are dealing with, and put a debugger inside

```auto
toString() {
  debugger;
  return "weird"
}

```

so you have a chance to see what’s the stack like, or look at the log to see where it might come from.

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [February 8, 2026, 9:54pm UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/13 "2026-02-08T21:54:32Z")

</div>

#### EDIT #2

It just occurred to me that maybe I’m not making myself clear on a particular point. I say this because a few times you’ve recommended setting `debugger` on a call to `toString`. The reason that’s not working is because the problem I’m calling out doesn’t involve a call to `toString`, but rather the adding of it to the object as a property.

So I wind up with an object that has `toString` on its prototype (as it should), and `toString` as a property of the object, like this:

```javascript
const someObject = {
   ...
   toString: function(value) {...} // tracked
   ...
}

someObject.prototype.toString = function(value) {...}

```

I can tell you that that’s nothing I’m doing. I’ve never before seen `toString` on an object twice, not to my recollection.

That might explain your puzzlement in the question to me earlier: “How did you get `toString` to be tracked?”

#### EDIT #1

You asked me earlier how I got `toString` to track. Actually, I didn’t. I have no idea how it’s happening. I’m not doing anything with `toString` anywhere.

Perhaps what follows will help…

#### ORIGINAL

@bigopon I tried your suggestion concerning `toString()` and I didn’t get anywhere with it (but it was a good thought).

The problem surfaced again in a different context, which is great because now I have a basis for comparison. It occurs now both in the context of my validation framework and in a rewrite I’m working on of a list component. Both of them involve bindables that are initialized to a plain object, and where in the view and/or a computed property, I use bracket notation to access the value of a property.

I can make the following statement as a sort of premise:

> In those cases where a `bindable` is a plain object initialized to `{},`_and_ the object is used in a computed property, _and_ the property does not exist, the bindable will pick up the following properties:
> 
> ![Screenshot 2026-02-08 at 2.44.07 PM](https://canada1.discourse-cdn.com/flex027/uploads/aurelia/optimized/2X/8/813d6d7de1849e1d92a1a2841b5e295f52502e6b_2_690x75.png)
> 
> where `toString` is not only on the prototype, but also on the object itself such that `Object.keys(someObject).length === 0` and `isEmpty(someObject)` are both `false` (`isEmpty` taken from lodash).

That explains in an earlier post why the problem was found in this computed on my model:

```javascript
@computed((model) => model.validation, { deep: true })
get hasValidationErrors() {
  return Object.keys(this.validation)?.some((_prop) => this.validation[_prop]?.isValid === false);
}

```

I do believe it is this that’s causing the problem (perhaps confusing Aurelia’s tracking system):

```javascript
this.validation[_prop]?.isValid

```

I say that because I have a very similar scenario in my handling of list selections:

```javascript
get isSelected() {
  return this.selected[this.item.id] ?? false;
}

```

where `selected` is also a `bindable` plain object initialized to `{}`.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [February 10, 2026, 12:41am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/14 "2026-02-10T00:41:21Z")

</div>

I don’t know how to help further without actually debugging it.

The reason I was suggesting adding to string/ or overriding to string was to check at which point `toString` was getting tracked. Another way to do it is to wrap the problematic object yourselves:

```auto
this.obj = new Proxy(this.obj, {
  get(target, key, receiver) {
    if (key === 'toString' && target.hasOwnProperty('toString')) {
      debugger; // where is this?
    }
  }
})

```

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [February 10, 2026, 1:58am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/15 "2026-02-10T01:58:35Z")

</div>

OK. That was a great idea! Perhaps we’ve gotten a little further on this.

I created a completely empty module within my project navigator. This is what I have for it as a test harness ( **this is the _totality_ of the code for the test harness** ):

**test-view.js**

```javascript
import { customElement } from 'aurelia';

@customElement('test-view')
export class TestView {
  constructor() {
    this.sourceObject = {};

    this.proxiedObject = new Proxy(this.sourceObject, {
      get(target, key, receiver) {
        if (key === 'toString' && target.hasOwnProperty('toString')) {
          debugger; // where is this?
        }
      },
    });
  }

  get hasValidationErrors() {
    return Object.keys(this.proxiedObject)?.some((_prop) => this.proxiedObject[_prop]?.isValid === false);
  }
}

```

and for the template:

**test-view.html**

```xml
<div class="tsi-bid-nav-view">Pricing</div>

<div>${hasValidationErrors}</div>

```

In the `hasValidationErrors` computed property, I set breakpoints just before `keys` in `Object.keys`, and just before `some` in `Object.keys(this.proxiedObject)?.some(...)`. I also set a breakpoint on the condition line of the proxied `get`.

**I hit the latter breakpoint first (in the proxied `get`), and never hit the other two breakpoints.**

This is what I see:

 ![Screenshot](https://canada1.discourse-cdn.com/flex027/uploads/aurelia/original/2X/d/dfc442e004c67c6d2b4bb68d5c3787db76e99e96.jpeg)

So, I changed the condition to this:

```javascript
this.proxiedObject = new Proxy(this.sourceObject, {
  get(target, key, receiver) {
    if (key.toString() === 'Symbol(Symbol.toStringTag)') { // <-- changed the condition
      debugger;
    }
  },
});

```

I had to eliminate `target.hasOwnProperty(…)` as that’s never satisfied without an ` __au_nw__ `error.

With this change, I was able to hit the debugger line. Here are the screenshots (left and right, respectively):

 ![Screenshot 2026-02-09 at 6.51.53 PM](https://canada1.discourse-cdn.com/flex027/uploads/aurelia/original/2X/b/b2b860bd0b065fe4f9c0399650467a0d58a968c5.png)

 ![Screenshot 2026-02-09 at 6.52.42 PM](https://canada1.discourse-cdn.com/flex027/uploads/aurelia/original/2X/c/c839bee84b335ff74eee1c0b43b29bec3bf1e97f.png)

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [February 10, 2026, 3:57am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/16 "2026-02-10T03:57:53Z")

</div>

Thanks, the stack helps. there is one line that mentions `content binding` which I think is the issue

it’s basically this:

![image](https://canada1.discourse-cdn.com/flex027/uploads/aurelia/original/2X/3/38d51e659efdad986adadc3a458aa691290ddb4f.png)

So it’s probably originated in a text binding of yours. Somehow the value wasn’t probably unwrapped at the point the text binding tried to get the string value.

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [February 10, 2026, 4:02am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/17 "2026-02-10T04:02:15Z")

</div>

#### EDIT #1

OK. I think what you’re referring to is **content-binding.ts**. But that’s not my code.

> So it’s probably originated in a text binding of yours.

In my post, I indicated that **test-view.js** and **test-view.html** are the only two files involved in testing for this issue. They might as well be in a repro on SB. Do you see a “text binding” anywhere in those two files that would produce this?

If not, then it’s a problem with the framework. If I stringify the plain object, the `toString` problem goes away, but the `toJSON` problem emerges.

Should I be putting together a repro?

#### ORIGINAL

I just searched my codebase. I don’t have this anywhere. Where’s it coming from? What would I be looking for?

What do you mean by `content binding`? I don’t have that anywhere either.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [February 10, 2026, 5:02am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/18 "2026-02-10T05:02:21Z")

</div>

I meant I’m quite fixed on where the unintentional tracking of `toString` is, it’s probably from a text binding. For the reason that the binding receives a proxy wrapped object and thus `.toString` was tracked. I’m not sure at which point it passed proxied objects around, so maybe a repro would really help. We can also do a blanket fix where we always unwrap the values in content binding before trying to get the string, but maybe a repro would be best.

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [February 10, 2026, 11:02pm UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/19 "2026-02-10T23:02:27Z")

</div>

Ah, I see. I misunderstood. I will put together a repro tomorrow. I’m slammed today.

But at least we’re on it now!

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [February 13, 2026, 4:22am UTC](https://discourse.aurelia.io/t/possible-bug-empty-plain-objects-pick-up-a-tostring-key-when-referenced-in-the-view-until-a-key-is-added-to-them/6583/20 "2026-02-13T04:22:08Z")

</div>

Hello @bigopon ,

I have created a repro on Stackblitz at this link:

> **[Aurelia 2.0RC (npx makes) - StackBlitz](https://stackblitz.com/edit/stackblitz-starters-uszgqnjr?file=README.md)**
>
> Repro to track unintentional toString and toJSON keys on empty object where a text binding is involved.

The call stack is different in devTools from what it is in VS Code. But I am hitting the `debugger` line successfully in the repro.

Please let me know if this helps.
