GitoxideLabs/gitoxide · error
internal nodes have no object ID key
Error message
internal nodes have no object ID key
What it means
`Node::key()` in `gix-note` returns the identifier for a note or subtree node; `Internal` fanout nodes carry no object-ID key, so the arm panics. Hitting it means the note-tree traversal stored/encountered an internal node where only leaf-bearing nodes are expected.
Solutions
- Report upstream with the notes tree shape (e.g. `git notes` output and fanout levels).
- Update `gix-note` to the latest version.
- If maintaining, make `key()` return `Option<&oid>` or an error for internal nodes.
Example fix
// before
Node::Internal(_) => unreachable!("internal nodes have no object ID key"),
// after
Node::Internal(_) => return Err(message("internal note node has no key")) Defensive patterns
Strategy: try-catch
Validate before calling
// Sanity-check the notes ref exists and looks like a note tree before use
// repo.find_reference("refs/notes/commits")?.peel_to_kind(gix_object::Kind::Tree)?; Try / catch
// Wrap note operations in catch_unwind or a subprocess if robustness matters. let out = std::panic::catch_unwind(|| notes.get(note_id));
Prevention
- Use current gix versions
- Test with fanout notes trees (e.g. repositories with many notes)
- Fuzz note insert/get/remove paths when contributing
When it happens
Trigger: Only if the note tree in-memory structure invariants break (e.g. a bug in `insert`/`load_subtree` placing an `Internal` node where `key()` is called). Not triggered by note content or repository data alone.
Common situations: Should never occur; would surface while inserting or looking up notes in a fanout-style notes tree if traversal logic regressed.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- the matching node was checked to be a subtree
- only value and unspecified are possible here
- parent-match assures this
- upper match already assured we only deal with blobs
- fixed size array with three items
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/6b994a4635d271e3.
Report an issue: GitHub.
Appendix: source
Thrown at gix-note/src/lib.rs:257
///
/// This performance-sensitive trie stores `prefix` and `prefix_len` separately so it can compare whole bytes
/// directly. Notes fanout advances by two hexadecimal digits at a time, so it does not need the nibble-granular
/// lengths supported by [`gix_hash::Prefix`].
prefix: ObjectId,
/// The number of leading bytes in `prefix` that are significant.
prefix_len: usize,
/// The slash-separated path from the notes root to this fanout subtree.
path: BString,
/// The object ID of the on-disk tree represented by this subtree.
tree_id: ObjectId,
}
impl Node {
fn key(&self) -> &oid {
match self {
Node::Note(note) => ¬e.annotated_object_id,
Node::Subtree(subtree) => &subtree.prefix,
Node::Internal(_) => unreachable!("internal nodes have no object ID key"),
}
}
}
impl Subtree {
fn contains(&self, id: &oid) -> bool {
self.prefix.as_bytes()[..self.prefix_len] == id.as_bytes()[..self.prefix_len]
}
}
impl InternalNode {
fn get(
&mut self,
annotated_object_id: &oid,
nibble: usize,
objects: &impl Find,
non_notes: &mut Vec<TreeEntry>,
) -> Result<Option<ObjectId>, Error> {View on GitHub (pinned to e73179060b)