From 613995c17540bc9ab7f20ddcedfee86f81443c7e Mon Sep 17 00:00:00 2001 From: Agi-Asi <206806952+Agi-Asi@users.noreply.github.com> Date: Fri, 28 Aug 2026 07:53:18 +0000 Subject: [PATCH] fix(devtools-kit): guard state editor against undefined path traversal When editing state from the component inspector (e.g. a Pinia store), the path used to locate the value may not exist on the target object. After traversing such a path, `StateEditor.set` did `this.refEditor.get(object)[field]` where `object` was `undefined`, throwing: `TypeError: this.refEditor.get(...) is undefined`. Stop the edit silently when the path does not resolve instead of throwing. Adds a regression test asserting a non-existing nested path does not throw. Closes #906 --- .../__tests__/component/editor.test.ts | 15 +++++++++++++++ .../src/core/component/state/editor.ts | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/packages/devtools-kit/__tests__/component/editor.test.ts b/packages/devtools-kit/__tests__/component/editor.test.ts index 96a2500d3..2403cbb58 100644 --- a/packages/devtools-kit/__tests__/component/editor.test.ts +++ b/packages/devtools-kit/__tests__/component/editor.test.ts @@ -89,6 +89,21 @@ describe('editor: StateEditor.set', () => { }) }) + describe('editComponentState: non-existing path should not throw', () => { + // https://github.com/vuejs/devtools/issues/906 + it('does not throw when the path points to an undefined value', () => { + const target = { foo: 'bar' } + const state = { newKey: '', type: '', value: 'baz' } + const defaultCallback = stateEditor.createDefaultSetCallback(state) + // `bar` does not exist on `target`, so traversal would previously hit + // `undefined[field]` and throw a TypeError. + expect(() => { + stateEditor.set(target, 'bar.baz', 'qux', defaultCallback) + }).not.toThrow() + expect(target).toEqual({ foo: 'bar' }) + }) + }) + describe('editComponentState: array', () => { it('modify value', () => { const target = ['foo', 'bar'] diff --git a/packages/devtools-kit/src/core/component/state/editor.ts b/packages/devtools-kit/src/core/component/state/editor.ts index 759bb2071..acfb9af41 100644 --- a/packages/devtools-kit/src/core/component/state/editor.ts +++ b/packages/devtools-kit/src/core/component/state/editor.ts @@ -28,8 +28,15 @@ export class StateEditor { else object = object[section] as Recordable if (this.refEditor.isRef(object)) object = this.refEditor.get(object) + // The path may not exist on the object (e.g. when editing a Pinia store + // from the component inspector). Stop instead of throwing a TypeError + // on `undefined[field]`. + if (object == null) + return } const field = sections[0] + if (object == null) + return const item = this.refEditor.get(object)[field] if (cb) { cb(object, field, value)