d2lang/d2 · error

malformed style setting, expected 2 part path

Error message

malformed style setting, expected 2 part path

What it means

When the reserved part of an edge/attribute key is `style`, the path must contain exactly two parts from the reserved index: `style` plus the style property (e.g. `style.opacity`). A shorter or longer remaining path is malformed for this branch and rejected.

Source

Thrown at d2oracle/edit.go:783

							return nil
						}
					case "label":
						if inlined(&arrowhead.Label) {
							arrowhead.Label.MapKey.SetScalar(mk.Value.ScalarBox())
							return nil
						}
					case "style":
						reservedTargetKey = mk.Key.Path[len(mk.Key.Path)-1].Unbox().ScalarString()
						if inlined(attrs.Style.Filled) {
							attrs.Style.Filled.MapKey.SetScalar(mk.Value.ScalarBox())
							return nil
						}
					}
				}
			case "style":
				if reservedTargetKey == "" {
					if len(mk.Key.Path[reservedIndex:]) != 2 {
						return errors.New("malformed style setting, expected 2 part path")
					}
					reservedTargetKey = mk.Key.Path[reservedIndex+1].Unbox().ScalarString()
				}
				switch reservedTargetKey {
				case "opacity":
					if inlined(attrs.Style.Opacity) {
						attrs.Style.Opacity.MapKey.SetScalar(mk.Value.ScalarBox())
						return nil
					}
				case "stroke":
					if inlined(attrs.Style.Stroke) {
						attrs.Style.Stroke.MapKey.SetScalar(mk.Value.ScalarBox())
						return nil
					}
				case "fill":
					if inlined(attrs.Style.Fill) {
						attrs.Style.Fill.MapKey.SetScalar(mk.Value.ScalarBox())
						return nil

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Use exactly `style.<property>`: `(a -> b).style.opacity`, `.style.stroke`, `.style.fill`, etc.
  2. Remove extra path segments after the property name.
  3. Validate the path length before calling: parse the key and check len(mk.Key.Path) from the reserved index.
  4. For nested arrowhead styles use the dedicated `source-arrowhead`/`target-arrowhead` branches instead of `style`.

Example fix

// before
g, err = d2oracle.Set(g, nil, "(a -> b).style", &opaque)
// after
g, err = d2oracle.Set(g, nil, "(a -> b).style.opacity", &opaque)
Defensive patterns

Strategy: validation

Validate before calling

mk, err := d2parser.ParseMapKey(key)
if err != nil { return err }
for i, p := range mk.Key.Path {
    if p.Unbox().ScalarString() == "style" {
        if len(mk.Key.Path)-i != 2 {
            return fmt.Errorf("style key %q must be exactly style.<property>", key)
        }
    }
}

Type guard

func styleKeyWellFormed(key string) bool {
    mk, err := d2parser.ParseMapKey(key)
    if err != nil { return false }
    for i, p := range mk.Key.Path {
        if p.Unbox().ScalarString() == "style" {
            return len(mk.Key.Path)-i == 2
        }
    }
    return true
}

Try / catch

err := d2oracle.Set(g, nil, key, &val)
if err != nil && strings.Contains(err.Error(), "malformed style setting, expected 2 part path") {
    return fmt.Errorf("use exactly style.<property> in %q", key)
}

Prevention

When it happens

Trigger: Calling d2oracle.Set/Create with a key like `(a -> b).style` (property missing) or a nested path with extra parts where len(mk.Key.Path[reservedIndex:]) != 2, e.g. `obj.style.opacity.extra` routed to this branch.

Common situations: Dropping the property name when composing keys programmatically; appending extra segments (e.g. index or nested key) that leave the wrong path length; copying object-level keys and mangling the style suffix.

Understand the failure class

Related errors


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/a52667aaafbb2ee4. Report an issue: GitHub.