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
- Rename your custom revset function to something namespaced/unique (e.g. myext::myfunc) so it cannot collide with built-ins or other extensions.
- 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.
- 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.
- 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
- Prefix custom revset function names with an extension namespace.
- Register custom functions in a single, idempotent init function.
- After upgrading jj, diff the built-in function list against your custom names.
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
- Conflicting factory definitions for '{}' factory
- cannot store git submodules
- SCM-aware Watchman clocks not supported
- ContentHash cannot be derived for unions.
AI-assisted analysis of jj-vcs/jj@c09b0c337f (2026-08-28).
Data as JSON: /api/errors/d2996c2d44315192.
Report an issue: GitHub.