Skip to content

Informative errors for variable names that marginaleffects overwrites (marginaleffects backend) - #679

Merged
strengejacke merged 11 commits into
easystats:mainfrom
jmgirard:focal-name-errors
Oct 15, 2026
Merged

strengejacke merged 11 commits into
easystats:mainfrom
jmgirard:focal-name-errors

Conversation

@jmgirard

Copy link
Copy Markdown
Contributor

This follows #677 and #678. With the marginaleffects backend, some variable names cannot work, because marginaleffects uses them for its own columns. marginaleffects::predictions() renames columns named Predicted, SE, CI_low and CI_high (reported as vincentarelbundock/marginaleffects#1771). marginaleffects also writes or uses s.value, df, predicted* and rowid itself. Before, these names gave wrong estimates, SEs or CIs, missing columns, or unclear errors such as "missing value where TRUE/FALSE needed". estimate_means(), estimate_contrasts() and estimate_slopes() now stop with an error that names the variable and asks users to rename it:

  • by variables of estimate_means(), and of estimate_contrasts() with a factor contrast: Predicted, SE, CI_low, CI_high, df, rowid, s.value.
  • a factor contrast variable: SE, CI_low, CI_high, df, rowid.
  • other predictors of estimate_means() and estimate_contrasts(): SE, CI_low, CI_high, df.
  • by variables of estimate_slopes(): df, rowid, s.value, predicted, predicted_hi, predicted_lo.

The check is .check_marginaleffects_names() in R/checks.R. It runs in get_marginalmeans() and get_marginaltrends() before the marginaleffects call, and it skips Bayesian models. estimate_slopes() with a by variable named SE, CI_low or CI_high keeps working with the .1 suffix from #678.

Some clashes come from modelbased itself, and these now work:

  • estimate_contrasts(by = "Level1") (or "Level2") gave two columns named Level1. The variable is now Level1.1.
  • estimate_contrasts(by = "hypothesis") did not split the contrast labels into Level1 and Level2, because marginaleffects names its own column hypothesis.1.
  • estimate_contrasts(m, "Parameter") failed, because the contrast labels were converted to the type of the Parameter variable and became NA.
  • If <name>.1 is already a variable, the suffix is now the next free number (for example p.2). Before, by = c("p", "p.1") gave a column p.1 with the values of p.

Not fixed here: Bayesian models, inequality comparisons, contrasts of slopes (numeric contrast variable), and the trend and covariate roles of estimate_slopes(). Some of these also give wrong output on main.

Tests in test-focal-name-clashes.R:

  • a loop over the 33 error cases that checks the message,
  • a grid over 14 names and 6 roles that compares each other combination with the same call for a variable named safe_var,
  • tests for Level1/Level2, hypothesis, Parameter and the free suffix.

Level1 and Level2 are removed from the "worked before" list for estimate_contrasts(by =). That test passed only because the duplicate column names matched the reference.

devtools::test() gives 0 failures and 0 errors locally. devtools::check() gives 0 errors and 0 warnings. The version is bumped to 0.17.0.14.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Targeted regression tests cover the changed behavior, and no unresolved issues were identified.

0 open findings

What changed in this PR

This PR makes the marginaleffects backend report variable-name collisions clearly instead of returning incorrect results or unclear errors. It also fixes several contrast-output name collisions.

Changes:

  • Add checks for variable names that marginaleffects reserves or overwrites.
  • Resolve contrast-column collisions and choose the next available suffix.
  • Add regression tests, update NEWS, and bump the development version.
File Description
tests/​testthat/​test-focal-name-clashes.R Tests errors, valid names, and collision handling.
R/​get_marginaltrends.R Checks names before calculating trends.
R/​get_marginalmeans.R Checks names before calculating means and contrasts.
R/​format.R Resolves contrast labels and focal-column suffixes.
R/​checks.R Defines the name-collision check and error.
NEWS.md Documents the behavior and remaining limitations.
DESCRIPTION Bumps the development version.

🧠 Review effort: Lite


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@strengejacke
strengejacke merged commit 45ab014 into easystats:main Oct 15, 2026
8 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants