dmtrKovalenko/fff · error
opts.base_path is null or empty
Error message
opts.base_path is null or empty
What it means
This sentinel validation error fires inside fff_create_instance_with when the FffCreateOptions.base_path field is a NULL pointer or an empty string, i.e. the caller asked to create a picker instance without telling the library which root directory to index. It is one of the argument-validation guards at the top of the function (alongside the null opts and unsupported-version checks), so it fires before any filesystem or index work begins and no instance is created. Callers hitting it are passing a struct whose base_path was never filled in or was zeroed/emptied by an earlier step.
Solutions
- Set opts.base_path to a non-empty, absolute path to the workspace root.
- If you want the current directory, resolve and pass cwd explicitly (e.g. getcwd()).
- In bindings, default the option to process cwd when unset instead of passing null/empty.
- Validate the base_path value at the binding layer before invoking the FFI call.
Example fix
// before opts.base_path = ""; // after opts.base_path = "/home/me/project"; // or resolved cwd
Defensive patterns
Strategy: validation
Validate before calling
if (typeof basePath !== 'string' || basePath.trim() === '') throw new Error('fff: base_path is required and must be non-empty'); Type guard
function hasBasePath(o) { return typeof o?.base_path === 'string' && o.base_path.trim().length > 0; } Try / catch
const base = cfg.workspace || process.cwd();
if (!hasBasePath({ base_path: base })) throw new Error('workspace root required');
opts.base_path = base; Prevention
- Default base_path to process.cwd() when unset.
- Validate config before instantiating the picker.
- Never pass empty strings for required FFI string fields.
- Document base_path as required in binding options.
When it happens
Trigger: Calling fff_create_instance_with with opts.base_path == NULL or pointing to an empty string ""; forgetting to fill base_path in a partially initialized options struct.
Common situations: Bindings that map an optional 'root' config option straight to base_path; a config file where the workspace path key is missing, producing an empty string; passing "" intending 'current directory'.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Instance handle is null. Create one with…
- opts is null
- Unsupported FffCreateOptions version
- Failed to init tracing
- Failed to acquire frecency lock
AI-assisted analysis of dmtrKovalenko/fff@7f8537e70f (2026-09-10).
Data as JSON: /api/errors/35e4c5a2574fb3cf.
Report an issue: GitHub.
Appendix: source
Thrown at crates/fff-c/src/lib.rs:197
/// is in the range `1..=FFF_CREATE_OPTIONS_VERSION`.
/// * All string pointers inside `opts` must be valid null-terminated UTF-8
/// or NULL.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn fff_create_instance_with(opts: *const FffCreateOptions) -> *mut FffResult {
if opts.is_null() {
return FffResult::err("opts is null");
}
let opts = unsafe { &*opts };
if opts.version == 0 || opts.version > FFF_CREATE_OPTIONS_VERSION {
return FffResult::err(&format!(
"Unsupported FffCreateOptions version {} (library understands up to {})",
opts.version, FFF_CREATE_OPTIONS_VERSION
));
}
let base_path_str = match unsafe { cstr_to_str(opts.base_path) } {
Some(s) if !s.is_empty() => s.to_string(),
_ => return FffResult::err("opts.base_path is null or empty"),
};
if let Some(log_path) = unsafe { optional_cstr(opts.log_file_path) } {
let level = unsafe { optional_cstr(opts.log_level) };
if let Err(e) = fff::log::init_tracing(log_path, level, None) {
return FffResult::err(&format!("Failed to init tracing: {}", e));
}
}
let frecency_path = unsafe { optional_cstr(opts.frecency_db_path) }.map(|s| s.to_string());
let history_path = unsafe { optional_cstr(opts.history_db_path) }.map(|s| s.to_string());
let shared_picker = SharedFilePicker::default();
let shared_frecency = SharedFrecency::default();
let query_tracker = SharedQueryTracker::default();
if let Some(ref frecency_path) = frecency_path {
if let Some(parent) = PathBuf::from(frecency_path).parent() {View on GitHub (pinned to 7f8537e70f)