Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions marimo/_ast/app_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ class _AppConfig:
# The type of SQL output to display
sql_output: SqlOutputType = "auto"

@staticmethod
def sanitize(updates: dict[str, Any]) -> dict[str, Any]:
"""Return only recognized config keys, silently dropping others."""
return {k: v for k, v in updates.items() if hasattr(_AppConfig, k)}

@staticmethod
def from_untrusted_dict(
updates: dict[str, Any], silent: bool = False
Expand Down
6 changes: 5 additions & 1 deletion marimo/_ast/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from marimo._convert.converters import MarimoConvert
from marimo._schemas.serialization import NotebookSerializationV1
from marimo._types.ids import CellId_t
from marimo._utils.marimo_path import MarimoPath
from marimo._version import __version__

if TYPE_CHECKING:
Expand Down Expand Up @@ -486,11 +487,14 @@ def generate_app_constructor(config: Optional[_AppConfig]) -> str:


def generate_filecontents_from_ir(ir: NotebookSerializationV1) -> str:
# Markdown frontmatter may contain non-config metadata (e.g., author,
# description). Suppress warnings for unrecognized keys from markdown.
silent = MarimoPath(ir.filename).is_markdown() if ir.filename else False
return generate_filecontents(
codes=[cell.code for cell in ir.cells],
names=[cell.name for cell in ir.cells],
cell_configs=[CellConfig.from_dict(cell.options) for cell in ir.cells],
config=_AppConfig.from_untrusted_dict(ir.app.options),
config=_AppConfig.from_untrusted_dict(ir.app.options, silent=silent),
header_comments=ir.header.value if ir.header else None,
)

Expand Down
11 changes: 10 additions & 1 deletion marimo/_ast/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from marimo import _loggers
from marimo._ast.app import App, InternalApp
from marimo._ast.app_config import _AppConfig
from marimo._ast.parse import (
MarimoFileError,
NonMarimoPythonScriptError,
Expand All @@ -18,6 +19,7 @@
UnparsableCell,
)
from marimo._session.notebook.serializer import get_notebook_serializer
from marimo._utils.marimo_path import MarimoPath

LOGGER = _loggers.marimo_logger()

Expand Down Expand Up @@ -80,7 +82,14 @@ def load_notebook_ir(
# Use filepath from notebook if not explicitly provided
if filepath is None:
filepath = notebook.filename
app = App(**notebook.app.options, _filename=filepath)

# Markdown frontmatter may contain non-config metadata (e.g., author,
# description). Filter to only pass recognized config keys to App().
options = notebook.app.options
if filepath and MarimoPath(filepath).is_markdown():
options = _AppConfig.sanitize(options)

app = App(**options, _filename=filepath)
for cell in notebook.cells:
if isinstance(cell, UnparsableCell):
app._unparsable_cell(cell.code, **cell.options)
Expand Down
1 change: 1 addition & 0 deletions marimo/_utils/variable_name.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Copyright 2026 Marimo. All rights reserved.
from __future__ import annotations

import inspect
Expand Down
40 changes: 40 additions & 0 deletions tests/_cli/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,46 @@ def test_cli_edit_new_file() -> None:
_check_contents(p, b'"serverToken": ', contents)


def test_cli_edit_markdown_no_config_warnings() -> None:
"""Markdown frontmatter metadata should not produce config warnings.

Regression test for https://github.com/marimo-team/marimo/issues/8259
"""
d = tempfile.TemporaryDirectory()
path = os.path.join(d.name, "notebook.md")
with open(path, "w") as f:
f.write(
"---\n"
"title: My Notebook\n"
"author: Test Author\n"
'description: "A test notebook"\n'
"---\n\n"
"```python {.marimo}\n"
"x = 1\n"
"```\n"
)

port = _get_port()
p = subprocess.Popen(
[
"marimo",
"edit",
path,
"-p",
str(port),
"--headless",
"--no-token",
"--skip-update-check",
],
stderr=subprocess.PIPE,
)
contents = _try_fetch(port)
assert contents is not None
p.kill()
_, stderr = p.communicate(timeout=5)
assert b"Unrecognized key" not in stderr


def test_cli_edit_with_additional_args(temp_marimo_file: str) -> None:
port = _get_port()
p = subprocess.Popen(
Expand Down
Loading