Skip to content

validate accepts a known field with the wrong type, the renderer drops it silently #188

Closed

Description

@LeadcodeDev

Symptom

Unknown attribute names have been errors since the attribute checker was hardened. Unknown attribute shapes are not: a known field given the wrong type passes validation and is discarded at render.

{"type":"text","content":"hello","position":{"x":60,"y":45},"style":{"font-size":24,"color":"#FFF"}}
$ rustmotion validate -f postest.json --strict-attrs
Notice: --strict-attrs is deprecated and does nothing.
Valid scenario: 1 scene(s) in 1 view(s)

position expects the string "absolute" with sibling x/y. Given an object it is silently ignored, the element falls back into flex flow, and nothing anywhere says so.

How it bites

This produced a scene where a cursor and its label were both laid out by flex instead of being anchored, and the cursor's auto_path offsets — which are relative to its own origin — threw it outside its card. The symptom (a stray bar in the wrong place) is a long way from the cause (a field quietly dropped).

Same class: duration as a string, padding as a value the Edges enum does not accept, a number where an enum is expected.

Note on what already works

The checker is not uniformly weak — Edges and the component-level parse do reject bad shapes loudly:

Error: ... invalid component — would be silently dropped at render: unknown field `padding-left`

That is exactly the right behaviour, and the model to extend: the gap is fields consumed outside the typed component parse.

Proposed fix

  1. Find the fields deserialised leniently outside the typed parse — position is one — and make their Deserialize reject a shape it cannot use rather than falling back to a default.
  2. Where a lenient fallback must stay for compatibility, emit the same would be silently dropped at render diagnostic the component parse already produces, so the wording and the JSON path stay consistent.
  3. A test per lenient field, asserting that a wrong-typed value is reported rather than defaulted.

Activity

  1. LeadcodeDev commented on Aug 12, 2026

    @LeadcodeDev
    OwnerAuthor

    Closing: this does not reproduce, and the premise was wrong.

    I filed it after a cursor cell laid out wrongly, blaming "position": {"x": 60, "y": 45} for being a known field given a bad shape. It is not — PositionMode is an untagged enum whose Absolute { x, y } variant is exactly that object form. Verified by rendering both spellings side by side:

    position: {x:300, y:20}      -> shape drawn at (300, 20)
    position: "absolute", x, y   -> shape drawn at (300, 120)
    

    Both are honoured. What actually misplaced that cell was the auto_path offsets, which are relative to the cursor's own origin — the cause established in #183.

    I then probed the class properly rather than assuming. The type checking is sound:

    input result
    duration: "3.0" rejected — invalid type: string "3.0", expected f64, with the path
    font-size: true rejected — would be silently dropped at render
    color: 16711680 rejected, same
    content: 42 rejected, same
    animation: {…} instead of […] accepted and honoured — verified by pixel, identical to the array form
    font-size: "20", gap: "12px", width: "100%" accepted, and legitimate: CSS lengths take strings

    So the two "silent" cases I listed are supported forms, not dropped ones, and the genuinely wrong types already fail loudly with their JSON path.

    The mistake was mine: I inferred a behaviour from a symptom instead of testing the behaviour. The Edges and component-level parses cited in the issue as "the model to extend" turn out to already be the behaviour throughout.

  2. self-assigned this
    on Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

invalidThis doesn't seem right

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions