Skip to content

Topmatter clobbers validated config values (heading_slug_func presets crash), and global_only is not enforced #1167

Description

@chrisjsewell

Found during review of the heading-anchors work (present on master since #1158; not introduced by it — the same mechanism affects any validated field).

---
myst:
  heading_slug_func: github
---

# Hello World

emits 'str' object is not callable [myst.heading_slug] for every heading, and no slugs are generated (same for any preset name).

Cause

In merge_file_level (myst_parser/config/main.py), the loop calls validate_field(...) — whose validator (check_heading_slug_func) resolves the preset string and sets the callable on the instance — but then follows with setattr(new, name, value), re-assigning the raw string over the validated value. compute_unique_slug later calls the string.

Separately, the field carries "global_only": True metadata, but that is only consumed by _docs.py (documentation generation) — merge_file_level neither respects it nor emits a "not allowed in topmatter" warning, so the user gets a confusing per-heading crash instead of a clear message.

Suggested fix

Two parts, probably one PR:

  1. merge_file_level: don't re-setattr the raw value after validation (use the validator's result / re-read the attribute), so validated fields keep their converted values.
  2. Enforce global_only in the topmatter path with a myst.topmatter warning naming the field, which for heading_slug_func (documented as global) is the behaviour users should actually see.

A regression test should cover both: a global-only field in topmatter → warning, and (if any per-document validated-and-converted field exists) that its converted value survives the merge.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions