Summary
When a variable-bound effect has its type changed (e.g. from Drop Shadow to Glass), the variable bindings from the original type persist on the effect object, attached to fields the new effect type does not have. As a result, effect.boundVariables can contain keys that are not valid parameters of the effect's current type. This is exposed through the Plugin API and is visible in the node's serialized effect data.
Environment
- Figma desktop, current release (observed August 2026)
- Plugin API; also reflected in
node.boundVariables.effects
Steps to reproduce
- Create a saved effect style for a Drop Shadow whose parameters are bound to variables - specifically
color,offsetX,offsetY,radius(blur), andspread. - Apply that effect style to a node.
- On that effect, change the effect type from Drop Shadow to Glass (which has no X/Y offset and no spread).
- Inspect the effect via the Plugin API:
node.effects[0].boundVariables.
Expected
After the type change to Glass, boundVariables should contain only keys valid for a Glass effect (e.g. color, radius, and Glass-specific fields). Bindings for fields that Glass does not expose (offsetX, offsetY, spread) should be dropped, since those parameters no longer exist on the effect.
Actual
The Glass effect retains the shadow-era bindings. boundVariables reports:
{
color: VariableID:…/shadow/active/color
offsetX: VariableID:…/shadow/active/x
offsetY: VariableID:…/shadow/active/y
radius: VariableID:…/shadow/active/blur
spread: VariableID:…/shadow/active/spread
}offsetX, offsetY, and spread are not parameters of a Glass effect and do not appear in the Glass effect UI, yet they remain bound in the data. The variable names themselves (…/shadow/active/x|y|blur|spread) confirm these are leftover shadow-token bindings clinging to an effect that can no longer use them.
Contrast (baseline that works correctly)
- A freshly created Glass effect reports
boundVariables: {}- correct. - The stale keys only appear after a type change from an effect that had those fields bound.
Impact
- Plugins that read
boundVariablesto report or manage variable bindings must now defensively intersect the keys against the valid field set for the currenteffect.type, or they will surface bindings that don't correspond to any real, editable parameter. - These orphaned bindings appear to be inert (Glass ignores them), but they are dead weight in the file and are confusing to tooling and, potentially, to variable-usage/impact analysis.
- It also raises a question about
spreadspecifically, which is only valid on certain node types even for shadows; so stalespreadbindings could compound existing validity constraints.
Suggested fix
On an effect type change, prune any boundVariables entries whose field is not a parameter of the new effect type (mirroring how the parameter values themselves are dropped/reset).
Notes
Happy to share full anonymized effect dumps (before/after the type change, plus the fresh-Glass baseline) if useful - they cleanly isolate the three states.
