jj-vcs/jj · critical

Conflict registering revset function '{name}'

Error message

Conflict registering revset function '{name}'

What it means

This panic occurs in RevsetAliasesMap/RevsetParseContext's add_custom_function (lib/src/revset.rs) when a custom revset function is registered under a name that is already present in the function map. Revset functions (like heads(x), parents(x)) are dispatched by name, so two registrations for the same name would make evaluation ambiguous. The library therefore panics on insert conflict instead of overwriting, surfacing configuration errors early.

Source

Thrown at lib/src/revset.rs:3520

    pub fn new() -> Self {
        Self {
            symbol_resolvers: vec![],
            function_map: BUILTIN_FUNCTION_MAP.clone(),
        }
    }

    pub fn symbol_resolvers(&self) -> &[Box<dyn SymbolResolverExtension>] {
        &self.symbol_resolvers
    }

    pub fn add_symbol_resolver(&mut self, symbol_resolver: Box<dyn SymbolResolverExtension>) {
        self.symbol_resolvers.push(symbol_resolver);
    }

    pub fn add_custom_function(&mut self, name: &'static str, func: RevsetFunction) {
        match self.function_map.entry(name) {
            hash_map::Entry::Occupied(_) => {
                panic!("Conflict registering revset function '{name}'")
            }
            hash_map::Entry::Vacant(v) => v.insert(func),
        };
    }
}

/// Information needed to parse revset expression.
#[derive(Clone)]
pub struct RevsetParseContext<'a> {
    pub aliases_map: &'a RevsetAliasesMap,
    pub local_variables: HashMap<&'a str, ExpressionNode<'a>>,
    pub user_email: &'a str,
    pub date_pattern_context: DatePatternContext,
    /// Special remote that should be ignored by default. (e.g. "git")
    pub default_ignored_remote: Option<&'a RemoteName>,
    pub fileset_aliases_map: &'a FilesetAliasesMap,
    pub extensions: &'a RevsetExtensions,
    pub workspace: Option<RevsetWorkspaceContext<'a>>,

View on GitHub (pinned to c09b0c337f)

Solutions

  1. Rename your custom revset function to something namespaced/unique (e.g. myext::myfunc) so it cannot collide with built-ins or other extensions.
  2. Audit init code and extension loading to ensure add_custom_function is called exactly once per name; cache the context rather than rebuilding it incrementally with duplicate inserts.
  3. If the name is now a built-in in a newer jj version, remove your custom registration and use the built-in, or pin the older version.
  4. Check the function_map before inserting and skip/warn instead of blindly calling add_custom_function.

Example fix

// before
ctx.add_custom_function("mine", mine_fn);
ctx.add_custom_function("mine", mine_fn); // panics

// after
ctx.add_custom_function("myext-mine", mine_fn); // unique name, inserted once
Defensive patterns

Strategy: validation

Validate before calling

// Guard before registering:
if ctx.function_map_contains(name) {
    eprintln!("revset function '{name}' already registered; skipping");
} else {
    ctx.add_custom_function(name, func);
}

Try / catch

// Panics unwind the process in Rust; prefer pre-checking. Last resort:
let r = std::panic::catch_unwind(|| ctx.add_custom_function(name, func));
if r.is_err() { /* log config error and continue */ }

Prevention

When it happens

Trigger: Calling add_custom_function("myfunc", ...) twice with the same name, or registering a custom function whose name collides with a built-in (e.g. "heads", "parents", "children") or with a function added by another extension/config layer. Typically triggered while assembling revset parse contexts or loading revset function extensions.

Common situations: A jj extension that defines a helper like mine(x) being loaded twice (e.g. listed in config under two extension mechanisms); a version upgrade adding a new built-in revset function that collides with a user-defined custom function of the same name; copy-pasted initialization code registering the same custom function in two places.

Related errors


AI-assisted analysis of jj-vcs/jj@c09b0c337f (2026-08-28). Data as JSON: /api/errors/d2996c2d44315192. Report an issue: GitHub.