{"record":{"id":"4fccb2d9a0f07e0b","repo":"jj-vcs/jj","slug":"cannot-store-git-submodules","errorCode":null,"errorMessage":"cannot store git submodules","messagePattern":"cannot store git submodules","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/src/simple_backend.rs","lineNumber":450,"sourceCode":"            id,\n            executable,\n            copy_id,\n        } => {\n            proto.value = Some(crate::protos::simple_store::tree_value::Value::File(\n                crate::protos::simple_store::tree_value::File {\n                    id: id.to_bytes(),\n                    executable: *executable,\n                    copy_id: copy_id.to_bytes(),\n                },\n            ));\n        }\n        TreeValue::Symlink(id) => {\n            proto.value = Some(crate::protos::simple_store::tree_value::Value::SymlinkId(\n                id.to_bytes(),\n            ));\n        }\n        TreeValue::GitSubmodule(_id) => {\n            panic!(\"cannot store git submodules\");\n        }\n        TreeValue::Tree(id) => {\n            proto.value = Some(crate::protos::simple_store::tree_value::Value::TreeId(\n                id.to_bytes(),\n            ));\n        }\n    }\n    proto\n}\n\nfn tree_value_from_proto(proto: crate::protos::simple_store::TreeValue) -> TreeValue {\n    match proto.value.unwrap() {\n        crate::protos::simple_store::tree_value::Value::TreeId(id) => {\n            TreeValue::Tree(TreeId::new(id))\n        }\n        crate::protos::simple_store::tree_value::Value::File(\n            crate::protos::simple_store::tree_value::File {\n                id,","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/jj-vcs/jj/blob/6631dbd4a85d5eb801aab321f7a9649ae3dc86ba/lib/src/simple_backend.rs#L432-L468","documentation":"tree_value_to_proto in lib/src/simple_backend.rs converts a jj TreeValue enum into the protobuf representation used by the simple (native jj) store. The proto schema has variants for File, Executable, Symlink, Tree, and Conflict — but no representation for GitSubmodule. Since git submodules (gitlink entries, mode 160000) cannot be expressed in the simple backend's on-disk format, attempting to serialize a tree entry containing one panics with 'cannot store git submodules'.","triggerScenarios":"Calling tree_value_to_proto (directly or via writing/serializing a tree Entry through the simple store backend, e.g. simple_store::tree::Entry construction or committing a tree) when a TreeValue::GitSubmodule is present in the tree — typically after importing a git commit that contains a submodule into a jj repo backed by the simple backend.","commonSituations":"Cloning or importing a Git repository that uses submodules into a jj repo without using the git-backed store; jj colocated vs non-colocated setups where the simple backend is the default; tooling that walks and re-serializes trees hitting an imported gitlink entry.","solutions":["Use a git-backed store/backend for the repo (jj git init / colocated repo) instead of the simple backend, since the simple store format has no submodule representation.","Strip or replace the GitSubmodule tree entries (e.g. by removing the submodule or converting the gitlink to a regular file/placeholder) before serializing the tree.","If you control the import, skip or warn on TreeValue::GitSubmodule entries instead of passing them to the simple backend.","Track/upgrade to a jj version with explicit submodule handling if one becomes available."],"exampleFix":"// before\nlet proto = tree_value_to_proto(value); // value is TreeValue::GitSubmodule -> panic\n\n// after\nmatch value {\n    TreeValue::GitSubmodule(_) => {\n        // skip or substitute: simple backend cannot represent gitlinks\n        return None;\n    }\n    other => Some(tree_value_to_proto(other)),\n}","handlingStrategy":"type-guard","validationCode":"// Before serializing a tree with the simple backend, scan for submodule entries:\nfn has_git_submodule(tree: &Tree) -> bool {\n    tree.entries().any(|e| matches!(e.value(), TreeValue::GitSubmodule(_)))\n}\nif has_git_submodule(&tree) { /* refuse or strip before tree_value_to_proto */ }","typeGuard":"fn is_simple_backend_storable(value: &TreeValue) -> bool {\n    !matches!(value, TreeValue::GitSubmodule(_))\n}","tryCatchPattern":"// Panic aborts; use catch_unwind only to convert to a clean error at the FFI/CLI boundary:\nmatch std::panic::catch_unwind(|| tree_value_to_proto(value)) {\n    Ok(proto) => proto,\n    Err(_) => return Err(anyhow!(\"tree contains a git submodule; use the git backend\")),\n}","preventionTips":["Prefer a git-backed (colocated) store for repos that contain or may receive submodules.","When importing git commits, check for mode-160000 entries and handle them explicitly.","Wrap serialization entry points with the is_simple_backend_storable guard."],"tags":["rust","jujutsu","git-submodules","serialization","simple-backend","unsupported-feature"],"backgroundTag":"unsupported-git-submodule-storage","analyzedSha":"6631dbd4a85d5eb801aab321f7a9649ae3dc86ba","analyzedAt":"2026-08-28T15:03:31.143Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}