diff --git a/src/hover.cpp b/src/hover.cpp
index f1fcd4e..fc6bc71 100644
--- a/src/hover.cpp
+++ b/src/hover.cpp
@@ -135,6 +135,7 @@ struct Sec_Hover_Fn {
   u64 &cur_field_off; // current field offset relative to the start of `data`
   // settings
   b8 display_grouped;
+  b8 old_version; // if true, treat the RNTuple as 0.x rather than 1.x
   // internals
   u8 cur_section_nesting = 0;
   u8 innermost_section_highlighted = 0;
@@ -440,17 +441,28 @@ struct Sec_Hover_Fn {
       if (!field<u16>("Flags: 0b%b", hover_display_val_le, &flags))
         return;
 
-      if (flags & RNTupleSerializer::kFlagRepetitiveField)
-        field_le<u64>("N Repetitions: %" PRIu64);
-      if (flags & RNTupleSerializer::kFlagProjectedField)
-        field_le<u32>("On disk proj.src id: %u");
-      if (flags & RNTupleSerializer::kFlagHasTypeChecksum)
-        field_le<u32>("Checksum: %u");
+      if (old_version) {
+        if (flags & RNTupleSerializer::kFlagRepetitiveField)
+          field_le<u64>("N Repetitions: %" PRIu64);
+        if (flags & RNTupleSerializer::kFlagProjectedField)
+          field_le<u32>("On disk proj.src id: %u");
+        if (flags & RNTupleSerializer::kFlagHasTypeChecksum)
+          field_le<u32>("Checksum: %u");
+      }
 
       field_str8<u32>("Name: %s");
       field_str8<u32>("Type Name: %s");
       field_str8<u32>("Type Alias: %s");
       field_str8<u32>("Description: %s");
+
+      if (!old_version) {
+        if (flags & RNTupleSerializer::kFlagRepetitiveField)
+          field_le<u64>("N Repetitions: %" PRIu64);
+        if (flags & RNTupleSerializer::kFlagProjectedField)
+          field_le<u32>("On disk proj.src id: %u");
+        if (flags & RNTupleSerializer::kFlagHasTypeChecksum)
+          field_le<u32>("Checksum: %u");
+      }
     });
   }
 
@@ -495,8 +507,12 @@ struct Sec_Hover_Fn {
       frame<Frame_List>("Extra Type Infos", [this] (u32 idx) {
         frame<Frame_Record>(push_str8f(arena, "Extra Type Info %u", idx).c(), [this] {
           field_le<u32>("Content identifier: %lu");
-          field_le<u32>("Type version from: %lu");
-          field_le<u32>("Type version to: %lu");
+          if (old_version) {
+            field_le<u32>("Type version from: %lu");
+            field_le<u32>("Type version to: %lu");
+          } else {
+            field_le<u32>("Type version: %lu");
+          }
         });
       });     
     });
@@ -889,9 +905,11 @@ struct Sec_Hover_Fn {
           frame<Frame_Record>("Schema Extension", [this] {
             schema_description("Schema Extension");
           });
-          frame<Frame_List>("Column Groups", [this] (u32) {
-            field_le<u32>("Column Id: %u");                  
-          });
+          if (old_version) {
+            frame<Frame_List>("Column Groups", [this] (u32) {
+              field_le<u32>("Column Id: %u");                  
+            });
+          }
           frame<Frame_List>("Cluster Groups", [this] (u32) {
             cluster_group();
           });
@@ -941,7 +959,7 @@ struct Sec_Hover_Fn {
 
 // `off` is the absolute offset into `data`.
 internal
-Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, const u8 *data, b8 display_grouped)
+Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, const u8 *data, b8 display_grouped, b8 old_version)
 {
   Sec_Hover_Info info {};
 
@@ -961,7 +979,7 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co
   }
 
   u64 cur_field_off = section.range.start - section.pre_size;
-  Sec_Hover_Fn hover { off, data, section, arena, info, cur_field_off, display_grouped };
+  Sec_Hover_Fn hover { off, data, section, arena, info, cur_field_off, display_grouped, old_version };
   
   switch (section.id) {
   case Sec_RNTuple_Anchor: 
diff --git a/src/render.cpp b/src/render.cpp
index f3fe825..57de613 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -251,7 +251,11 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
   if (ImGui::Begin("main", nullptr, main_win_flags)) {
         
     String8 ntpl_desc = rntuple_description(scratch.arena, app.tfile_data.rntuple_anchor);
-    ImGui::Text("RNTuple '%s' (%s) from file \"%s\"", app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c());
+    if (rntuple_is_old_version(app.tfile_data.rntuple_anchor))
+      ImGui::TextColored(ImColor(1.f, 0.f, 0.f), "RNTuple '%s' (%s) from file \"%s\" ** old version, some data missing! **", 
+                         app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c());
+    else
+      ImGui::Text("RNTuple '%s' (%s) from file \"%s\"", app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c());
 
     // Draw stats
     {
@@ -398,12 +402,13 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
 
       if (hovered_off)
       {
+        const ROOT::RNTuple &anchor = app.tfile_data.rntuple_anchor;
         ImGui::TextColored(ImColor(0.f, 0.65f, 0.f), "Offset: 0x%" PRIX64, hovered_off - 1);
         Section hovered_section = find_section(app, hovered_off - 1);
         b8 hover_display_grouped = !(app.user_input.key_state[KEY_ALT] & KEY_STATE_IS_DOWN);
+        b8 old_version = rntuple_is_old_version(anchor);
         Sec_Hover_Info hover_info = get_section_hover_info(scratch.arena, hovered_section, hovered_off - 1, 
-                                                           app.inspected_file.mem, hover_display_grouped);
-        const ROOT::RNTuple &anchor = app.tfile_data.rntuple_anchor;
+                                                           app.inspected_file.mem, hover_display_grouped, old_version);
         b8 header_is_compressed = anchor.GetNBytesHeader() != anchor.GetLenHeader();
         if (!header_is_compressed)
           ImGui::TextColored(ImColor(0.5f, 0.5f, 0.5f), "(Hint: press Alt for single-field hover information)");
diff --git a/src/rntuple.cpp b/src/rntuple.cpp
index dae56cf..0d3de8d 100644
--- a/src/rntuple.cpp
+++ b/src/rntuple.cpp
@@ -1,3 +1,9 @@
+internal
+b8 rntuple_is_old_version(const ROOT::RNTuple &ntuple)
+{
+  return ntuple.GetVersionEpoch() == 0 && ntuple.GetVersionMajor() < 3;
+}
+  
 internal
 String8 rntuple_description(Arena *arena, const ROOT::RNTuple &ntuple)
 {
@@ -23,6 +29,8 @@ ROOT::Experimental::RNTupleDescriptor create_descriptor(Arena *arena, const TFil
   defer { scratch_end(scratch); };
 
   const ROOT::RNTuple &anchor = tfile_data.rntuple_anchor;
+  if (rntuple_is_old_version(anchor))
+    fprintf(stderr, "Warning: the RNTuple being read is an old version. We'll probably fail to read some metadata.\n");
   
   // Read compressed header+footer
   u8 *header_zip = arena_push_array_nozero<u8>(scratch.arena, anchor.GetNBytesHeader());
@@ -39,8 +47,8 @@ ROOT::Experimental::RNTupleDescriptor create_descriptor(Arena *arena, const TFil
   // Deserialize header+footer
   RNTupleDescriptorBuilder desc_builder;
   try {
-    RNTupleSerializer::DeserializeHeader(header, anchor.GetLenHeader(), desc_builder);
-    RNTupleSerializer::DeserializeFooter(footer, anchor.GetLenFooter(), desc_builder);
+    RNTupleSerializer::DeserializeHeader(header, anchor.GetLenHeader(), desc_builder).ThrowOnError();
+    RNTupleSerializer::DeserializeFooter(footer, anchor.GetLenFooter(), desc_builder).ThrowOnError();
   } catch (...) {
     fprintf(stderr, "Failed to deserialize header/footer!\n");
   }
diff --git a/test_old.root b/test_old.root
deleted file mode 100644
index bbdcc88..0000000
Binary files a/test_old.root and /dev/null differ
diff --git a/test_uncomp_old.root b/test_uncomp_old.root
deleted file mode 100644
index 735d3d4..0000000
Binary files a/test_uncomp_old.root and /dev/null differ