dmtrKovalenko/fff · error

Instance handle is null. Create one with…

Error message

Instance handle is null. Create one with fff_create_instance first.

What it means

The C FFI instance_ref helper converts the opaque void* handle into a &FffInstance. A null handle means no instance was ever created (or it was freed), so any search/glob/grep call fails immediately. The library requires fff_create_instance first.

Solutions

  1. Check the FffResult from fff_create_instance before using the handle.
  2. Ensure the handle returned by fff_create_instance is stored and passed to every subsequent call.
  3. In bindings, guard against null before calling search functions (throw a clear error instead).
  4. Verify create/free ordering so the handle is not used after being freed.

Example fix

// before
const res = fff_search(null, query);
// after
const handle = fff_create_instance(opts);
if (handle === null) throw new Error('failed to create fff instance');
const res = fff_search(handle, query);
Defensive patterns

Strategy: type-guard

Validate before calling

if (handle === null || handle === undefined) throw new Error('fff instance not created; call fff_create_instance first');

Type guard

function hasInstance(h) { return h !== null && h !== undefined && !h.equals(ffi.NULL); }

Try / catch

if (!hasInstance(handle)) {
  throw new Error('fff instance handle missing; create it with fff_create_instance first');
}
const res = fff_search(handle, query);
if (!res.ok) handleFffError(res);

Prevention

When it happens

Trigger: Calling fff_search, fff_glob, fff_search_directories, fff_search_mixed, fff_live_grep_ex, or fff_multi_grep_ex with a null/zeroed handle, or a handle from a failed fff_create_instance call, or after fff_free_instance double-use.

Common situations: Ignoring the error result of fff_create_instance and proceeding with the null handle; FFI marshalling bug in a binding layer dropping the pointer; using the handle after library shutdown.

Related errors


AI-assisted analysis of dmtrKovalenko/fff@7f8537e70f (2026-09-10). Data as JSON: /api/errors/ed535fab9cd73375. Report an issue: GitHub.

Appendix: source

Thrown at crates/fff-c/src/lib.rs:63

    if s.is_null() {
        None
    } else {
        unsafe { CStr::from_ptr(s).to_str().ok() }
    }
}

/// Optional C string param: `None` if null, empty, or invalid UTF-8.
unsafe fn optional_cstr<'a>(s: *const c_char) -> Option<&'a str> {
    unsafe { cstr_to_str(s) }.filter(|s| !s.is_empty())
}

/// Recover a `&FffInstance` from the opaque pointer; error `FffResult` if null.
pub(crate) unsafe fn instance_ref<'a>(
    fff_handle: *mut c_void,
) -> Result<&'a FffInstance, *mut FffResult> {
    if fff_handle.is_null() {
        Err(FffResult::err(
            "Instance handle is null. Create one with fff_create_instance first.",
        ))
    } else {
        Ok(unsafe { &*(fff_handle as *const FffInstance) })
    }
}

/// Decode a `u8` grep mode into the core enum.
fn grep_mode_from_u8(mode: u8) -> fff::GrepMode {
    match mode {
        1 => fff::GrepMode::Regex,
        2 => fff::GrepMode::Fuzzy,
        _ => fff::GrepMode::PlainText,
    }
}

/// Apply "0 means default" convention.
fn default_u32(val: u32, default: u32) -> u32 {
    if val == 0 { default } else { val }

View on GitHub (pinned to 7f8537e70f)