matter.js version
0.17.9
Node.js version
v24.18.0
Operating system
Ubuntu Linux 6.17.0-35-generic, x86_64
Description
What I did:
Built a CommodityTariff cluster server (feature Pricing only, Randomization NOT enabled) on an
endpoint, then used endpoint.setStateOf(CommodityTariffServer, { dayEntries: [...], ... }) (via
Matterbridge's setAttribute() helper) to publish a flat-rate day schedule after the endpoint was
already installed/active. The dayEntries value was:
dayEntries: [{ dayEntryId: 1, startTime: 0 }]
i.e. a plain DayEntryStruct with only the two mandatory fields (DayEntryId, StartTime) — no
RandomizationOffset/RandomizationType key at all.
What I expected:
The write to succeed, since RandomizationType's conformance ([RNDM]) means the field must be
absent when the Randomization feature isn't enabled — and I never supplied it.
What happened:
The write is rejected:
Validating Matterbridge.Matterbridge.electricalMeter1.electricalMeterCurrent.commodityTariff.state.0.randomizationType:
Conformance "[RNDM]": Matter does not allow you to set this attribute (135)
Full stack trace (from the attached log, matterbridge-commoditytariff-bug.log):
Error: Validating Matterbridge.Matterbridge.electricalMeter1.electricalMeterCurrent.commodityTariff.state.0.randomizationType: Conformance "[RNDM]": Matter does not allow you to set this attribute (135)
at disallowValue (file:///.../node_modules/@matter/node/dist/esm/behavior/state/validation/conformance-compiler.js:432:13)
at Object.randomizationType (file:///.../node_modules/@matter/node/dist/esm/behavior/state/validation/conformance.js:20:19)
at validateStruct (file:///.../node_modules/@matter/node/dist/esm/behavior/state/validation/ValueValidator.js:275:23)
at file:///.../node_modules/@matter/node/dist/esm/behavior/state/validation/ValueValidator.js:30:7
at file:///.../node_modules/@matter/node/dist/esm/behavior/state/validation/conformance.js:28:22
at validateEntries (file:///.../node_modules/@matter/node/dist/esm/behavior/state/validation/ValueValidator.js:320:11)
...
Analysis:
Looking at the Matter model source (@matter/model/src/standard/elements/commodity-tariff.element.ts):
Field({ name: "RandomizationOffset", id: 0x3, type: "int16", conformance: "[RNDM]" }),
Field({
name: "RandomizationType", id: 0x4, type: "DayEntryRandomizationTypeEnum", conformance: "[RNDM]",
default: 0
})
RandomizationType is declared with both:
conformance: "[RNDM]" — the field must be entirely absent unless the Randomization feature is
enabled (which I don't have — only Pricing).
default: 0 — an unconditional default value.
When the write path (endpoint.setStateOf() → the attribute-server validated write, as opposed to
behaviors.require()'s initial-injection path, which does not hit this) canonicalizes the partial
DayEntryStruct I supplied against the full model, it fills the missing randomizationType key with
its declared default (0) — and then the conformance validator rejects that very same auto-filled
value for violating the [RNDM] gate. The model's own default-filling and its own conformance rule
contradict each other for any consumer that doesn't enable Randomization.
Confirmed this only affects the list-attribute write path: writing a single DayEntryStruct
attribute (e.g. currentDayEntry) with the exact same shape ({ dayEntryId, startTime }) succeeds
without error — only dayEntries (List[DayEntryStruct]) triggers the crash. So the bug is specific
to how struct defaults are filled/validated for list-attribute elements versus a bare struct attribute.
Proposed fix (not verified against the codebase, just a hypothesis):
Either:
RandomizationType/RandomizationOffset should have no default in the model (leave them
undefined when absent, so canonicalization doesn't synthesize a value that then fails its own
conformance check), or
- the conformance validator should treat an auto-filled default value for a
[FEATURE]-gated
optional field as "absent" rather than "set", when the caller never supplied it explicitly, or
- struct defaulting inside
List[Struct] attribute writes should follow the same (working) code path
used for a bare struct attribute write.
Full log attached (matterbridge-commoditytariff-bug.log, ~1300 lines): covers plugin/endpoint
construction, the three preceding successful setAttribute() calls (tariffInfo, tariffUnit,
startDate — all succeed), the failing dayEntries write, the rollback, and the full stack trace.
Reached through Matterbridge (a wrapper around matter.js), but the failing call is a plain
endpoint.setStateOf(CommodityTariffServer, { dayEntries: [...] }) — no Matterbridge-specific logic is
involved in the failure itself.
matterbridge-commoditytariff-bug.log
Confirmation
matter.js version
0.17.9
Node.js version
v24.18.0
Operating system
Ubuntu Linux 6.17.0-35-generic, x86_64
Description
What I did:
Built a
CommodityTariffcluster server (featurePricingonly,RandomizationNOT enabled) on anendpoint, then used
endpoint.setStateOf(CommodityTariffServer, { dayEntries: [...], ... })(viaMatterbridge's
setAttribute()helper) to publish a flat-rate day schedule after the endpoint wasalready installed/active. The
dayEntriesvalue was:i.e. a plain
DayEntryStructwith only the two mandatory fields (DayEntryId,StartTime) — noRandomizationOffset/RandomizationTypekey at all.What I expected:
The write to succeed, since
RandomizationType's conformance ([RNDM]) means the field must beabsent when the
Randomizationfeature isn't enabled — and I never supplied it.What happened:
The write is rejected:
Full stack trace (from the attached log,
matterbridge-commoditytariff-bug.log):Analysis:
Looking at the Matter model source (
@matter/model/src/standard/elements/commodity-tariff.element.ts):RandomizationTypeis declared with both:conformance: "[RNDM]"— the field must be entirely absent unless theRandomizationfeature isenabled (which I don't have — only
Pricing).default: 0— an unconditional default value.When the write path (
endpoint.setStateOf()→ the attribute-server validated write, as opposed tobehaviors.require()'s initial-injection path, which does not hit this) canonicalizes the partialDayEntryStructI supplied against the full model, it fills the missingrandomizationTypekey withits declared default (
0) — and then the conformance validator rejects that very same auto-filledvalue for violating the
[RNDM]gate. The model's own default-filling and its own conformance rulecontradict each other for any consumer that doesn't enable
Randomization.Confirmed this only affects the list-attribute write path: writing a single
DayEntryStructattribute (e.g.
currentDayEntry) with the exact same shape ({ dayEntryId, startTime }) succeedswithout error — only
dayEntries(List[DayEntryStruct]) triggers the crash. So the bug is specificto how struct defaults are filled/validated for list-attribute elements versus a bare struct attribute.
Proposed fix (not verified against the codebase, just a hypothesis):
Either:
RandomizationType/RandomizationOffsetshould have nodefaultin the model (leave themundefinedwhen absent, so canonicalization doesn't synthesize a value that then fails its ownconformance check), or
[FEATURE]-gatedoptional field as "absent" rather than "set", when the caller never supplied it explicitly, or
List[Struct]attribute writes should follow the same (working) code pathused for a bare struct attribute write.
Full log attached (
matterbridge-commoditytariff-bug.log, ~1300 lines): covers plugin/endpointconstruction, the three preceding successful
setAttribute()calls (tariffInfo,tariffUnit,startDate— all succeed), the failingdayEntrieswrite, the rollback, and the full stack trace.Reached through Matterbridge (a wrapper around matter.js), but the failing call is a plain
endpoint.setStateOf(CommodityTariffServer, { dayEntries: [...] })— no Matterbridge-specific logic isinvolved in the failure itself.
matterbridge-commoditytariff-bug.log
Confirmation