25.9 I. Common ROOT Errors and Solutions
Table of Contents
Overview
ROOT is powerful, but beginners often meet the same small set of problems. This appendix summarizes frequent errors, what they usually mean, and practical ways to fix or avoid them. It is not a full debugging guide, but a quick reference you can consult when something “suddenly stops working.”
Whenever you see an error, try to read the entire message carefully. ROOT often tells you which object or file is missing, which line in a macro failed, or which pointer is null. Most of the problems below are variations of a few themes: wrong file paths, object ownership, histogram ranges, TTrees and branches, and misconfigured fits.
Always check:
- Is the object or file really created or opened successfully?
- Is the pointer non-null before you use it?
- Are the histogram ranges and bin definitions appropriate?
- Are branch names and types correct?
- Are fit ranges and initial parameters reasonable?
Library Loading and Interpreter Errors
One frequent class of problems occurs before you even start the analysis logic. ROOT either cannot understand your code or cannot find required libraries.
Typical messages include:
error: unknown type name 'TH1F'error: no member named 'Draw' in 'TH1F'cling::DynamicLibraryManager::loadLibrary(): ... cannot open shared object fileIncrementalExecutor::executeFunction: symbol not found
These usually indicate either that you are missing an include, or that a compiled macro or external library was not loaded.
First check that you included the right ROOT header at the top of your macro. For example, for histograms you need #include "TH1F.h" or more generally #include "TH1.h". For canvases use #include "TCanvas.h", for TTrees #include "TTree.h", and so on. In interactive ROOT you can include these headers directly, or rely on ROOT’s automatic header loading, but having explicit includes in macros is safer.
If the error mentions a missing symbol when running a compiled macro or an external library, verify that you compiled the code correctly with ACLiC or with root-config flags, and that ROOT can see the .so (or .dll) file. For example, if you built libMyAnalysis.so in the current directory, load it explicitly with .L libMyAnalysis.so. Pay attention to the exact function or symbol name in the error, it often includes the namespace or class name and helps you find what was not linked.
When the interpreter complains about C++ syntax, such as error: expected ';' after expression or use of undeclared identifier, go to the line number reported in the error, not just the last line of the message. Many syntax errors are caused by a missing semicolon in a previous line, or a missing brace that changes the structure of the entire function.
File and Path Errors
ROOT relies heavily on external files, especially .root files. Many problems occur because a file is not where you think it is, or because it was opened in the wrong mode.
Common symptoms include:
Error in <TFile::TFile>: file mydata.root does not existTFile* f = TFile::Open("mydata.root");followed by a crash when you usefError in <TFile::Open>: cannot open file mydata.rootError in <TKey::ReadObj>: Object histName is not of type TH1F, but TH1D
First ensure that the file name and path are correct. If you are using relative paths, remember that ROOT’s current working directory is wherever you started ROOT or your macro. Use gSystem->pwd(); or gSystem->cd("..."); to check and change the working directory, or use absolute paths.
After you call TFile::Open, always check that the returned pointer is not null and that the file is actually open. For example, if (!f || f->IsZombie()) { / handle error / }. A “zombie” file means that ROOT created a placeholder object but opening failed. Never use a zombie file in subsequent code, since that often leads to null pointers or missing objects.
If you cannot retrieve an object from a file, double check the name and class type. Use file->ls(); to see what is actually stored. Sometimes you think you stored a histogram as hEnergy but the name is h_energy or the object type is different from what you expect. If ROOT reports a type mismatch when using Get, that means you requested the wrong class type, for example casting the object to TH1F when the stored object is a TH1D.
When writing files, remember to close them properly. If you forget to call file->Write(); or file->Close();, your output file may be incomplete or empty. This often surfaces later as “file does not contain histogram X” even though the macro ran without visible errors.
Null Pointers and Missing Objects
Many runtime crashes and segmentation faults result from dereferencing a null pointer. In ROOT, this often happens with histograms, TTrees, or objects retrieved from files or directories.
Typical manifestations:
Segmentation violationwhen you callh->Fill(...)buthis not created.Error in <TObject::ReadObj>: ...followed by a crash when callingDraw()on a missing object.- Pointer variables that were never initialized, or objects that went out of scope.
Always ensure that pointers are initialized and that objects exist before you access them. For example, if you retrieve a histogram via TH1F h = (TH1F)file->Get("hName"); then immediately check if (!h) { / handle missing histogram / }. Do not assume that Get always succeeds.
Be careful with object lifetimes. If you create an object as a local variable inside a function, and return a pointer to it, the object will be destroyed when the function ends. A later call to Draw() on that pointer can crash, because the memory was freed. To avoid this, either create objects on the heap with new, or manage them with ROOT directories and the appropriate ownership rules.
Null pointer issues are particularly common when combining ROOT with C++ standard containers. For example, if you push back pointers to histograms into a std::vector<TH1F*>, you must ensure those histograms remain alive for as long as you need them. Do not let them be destroyed at the end of a shorter scope.
Before you call methods like Fill(), Draw(), or Write() on a pointer, always verify:
- The pointer is not null.
- The object is still in scope or has not been deleted.
TObject Ownership and “Object Deleted” Problems
ROOT has its own memory and ownership model. Many objects are owned by directories or canvases, and ROOT may delete them when you do not expect it. This leads to errors such as:
Error in <TObject::Streamer>: The object named ... is not in the TFile directory- Crashes when redrawing a canvas after closing a file that contained the histograms.
- Histograms disappearing after a macro ends, especially when you created them on the stack.
A typical issue occurs when you create a histogram without specifying a directory, and then close the TFile that owned it. ROOT automatically deletes many objects when their owning directory or file is closed. Later attempts to use the histogram pointer will fail, sometimes silently.
To avoid surprises, know which directory your objects belong to. You can use h->GetDirectory() to see it. For histograms that you want to keep independent of files, you can detach them from any directory by calling h->SetDirectory(0);. This is especially useful when you read histograms from a file, copy or clone them, and then close the file. The clone should be detached to survive the file closing.
Similarly, canvases can own the objects drawn on them. If you create histograms as local variables inside a macro and draw them on a canvas, they may be destroyed when the macro ends, while the canvas remains on screen. Interacting with the canvas later can then crash ROOT. To prevent this, create long-lived objects on the heap with new or manage their lifetime at the same scope as the canvas.
Multiple deletions are another ownership-related problem. If ROOT owns an object and will delete it automatically, you must not delete it manually. Deleting the same object twice can produce segmentation faults or subtle memory corruption. Learn which factory methods transfer ownership to the caller and which ones return owned objects that ROOT will manage.
Histogram Range and Binning Problems
Many “wrong” plots and suspicious fit results are not caused by ROOT itself but by inappropriate histogram configuration. Common symptoms include:
- Histograms that appear empty even though you call
Fill(). - Peaks that are cut off at the edge of the histogram.
- Underflow or overflow statistics that are very large.
- Fitted means or RMS values that make no sense.
In most cases, the problem is that your data values fall outside the histogram range or are concentrated in only a few bins. Check the histogram definition. For example, if you define TH1F("h", "h", 100, 0.0, 1.0) but your data range is from 0 to 1000, virtually all entries will go to the overflow bin and the drawing will look empty. Use the methods that report underflow and overflow, or print h->GetBinContent(0) and h->GetBinContent(nb+1) where nb is the number of bins.
If a peak is located exactly at the edges, consider expanding the range slightly to avoid truncation. Also check that you use the right type (TH1F vs TH1D) for your expected precision and dynamic range. Using too few bins can hide structure, and using too many bins with a small event count can produce noisy distributions.
When comparing histograms, ensure that they have compatible binning. Adding, subtracting, or dividing histograms with different ranges or bin numbers can produce cryptic error messages or meaningless results. ROOT will usually warn about incompatible histograms, but you should design consistent binning yourself from the start.
Before trusting a histogram:
- Verify that its range covers your data.
- Inspect underflow and overflow contents.
- Confirm that binning is appropriate for statistics and resolution.
TTree and Branch Problems
TTrees are central to ROOT analyses, and many issues arise when reading or writing branches. Messages and symptoms include:
unknown branch: varNamewhen usingTTree::Draw.- All entries appear to be zero or uninitialized when looping.
- Crashes when reading from branches, often due to wrong types.
Error in <TBranchElement::Fill>: ...during writing.
First check branch names. Typos in TTree::Draw("varName") simply yield empty histograms without crashing, which can be misleading. Use tree->Print(); or tree->GetListOfBranches()->Print(); to list the actual branch names and types.
When reading with SetBranchAddress, the variable type must exactly match the branch type. If the branch is Float_t, use float or Float_t in C++. If the branch is a std::vector<double>, you must use a compatible pointer to std::vector<double>. Mismatched types can cause segmentation faults or corrupt values silently.
If you see constant or zero values for a branch while looping, check that you called SetBranchAddress before entering the event loop, and that you call GetEntry(i) inside the loop for the correct tree. Also ensure that your variable is not being overwritten by some other code inside the loop.
When writing TTrees, confirm that you create branches correctly and call tree->Fill(); for each event. Forgetting a Fill before closing the file leads to an empty tree. If you modify the structure of a tree midway through writing, some branches may contain fewer entries than others. Later reading operations must be aware of that, especially when combining multiple trees with TChain.
ROOT File and Directory Issues
ROOT files can contain directories, trees, histograms, and more. Problems often come from confusion about the current directory or from writing objects under unexpected names or paths.
Common situations:
- Writing a histogram to a file, then not finding it with a simple
Get("hName"). - Saving objects in subdirectories, then forgetting to navigate there for reading.
- Using the same name for different objects, leading to overwrites.
When writing, be explicit about the file and directory that should own the object. If you open a file and then create a histogram, that file’s current directory usually becomes the owner. If you want to organize objects in subdirectories, create a TDirectory with file->mkdir("subdir"); and then cd into it. Always check with file->ls(); or gDirectory->ls(); to confirm where objects ended up.
On reading, if you know that a histogram resides in a subdirectory, use the full path when retrieving, for example file->Get("subdir/hName"). If you just call Get("hName") from the top-level file, ROOT may return null even though the object exists deeper in the structure.
Also be careful with automatic overwriting. Creating a new object with the same name in the same directory typically overwrites the previous one in the file. If you want to preserve multiple versions, change the name or add a suffix, perhaps with run numbers or timestamps.
Fitting and Minimization Errors
Fit-related problems are very common, especially for beginners. Even when ROOT does not show a hard error, the fit may fail or give meaningless parameter values. Typical signs include:
- Warning messages like
Error in <TMinuit::Mnvert>: Matrix inversion failsorFit chi2/ndf = 0 / 0. - Parameters taking extreme or unphysical values.
- Fit curves that obviously do not match the data.
The most frequent causes are poor initial parameter guesses, inappropriate fit ranges, insufficient statistics, or unsuitable models. Always choose a reasonable fit range that covers the region where the model is expected to describe the data. For example, fitting a Gaussian only around the peak rather than across a broad background often works better.
Set initial parameters explicitly when possible. For a Gaussian, use approximate estimates of the height, mean, and sigma from the histogram. ROOT can sometimes guess them, but not always correctly. You can call func->SetParameters(...) before calling Fit, or specify initial values directly in the TF1 constructor for simple functions.
When the fit converges badly or not at all, try relaxing or setting parameter limits. For example, if you know the width must be positive, set lower bounds, but avoid overly tight limits that prevent the minimizer from exploring the parameter space.
If the chi-square is extremely low or high, or the number of degrees of freedom is zero, inspect the number of points being used and the bin errors. Missing errors or incorrectly computed uncertainties can make the fit meaningless. For histograms with low entries per bin, using Poisson appropriate likelihood fits rather than chi-square may be necessary, although that goes beyond basic usage.
For reliable fits:
- Select an appropriate fit range.
- Provide reasonable initial parameter values.
- Check fit messages, chi-square, and parameter uncertainties.
Graphics and Drawing Problems
Graphics issues usually do not crash ROOT, but they can make plots confusing or invisible. Symptoms include:
- An empty canvas even though the histogram has entries.
- Histograms or graphs not updating after a macro finishes.
- Objects being drawn on top of each other unintentionally.
- Axes or labels not appearing as expected.
Root canvases are not automatically updated in all contexts. After drawing objects in a compiled macro, you might need to call c1->Update(); at the end to trigger a redraw when running non-interactively. In batch mode with gROOT->SetBatch(kTRUE);, canvases are not shown on screen at all, only saved to files.
If a canvas looks empty, verify that you actually called Draw() on an object, and that the object contains data. Zoomed-out axes can make small features invisible, so check the axis ranges or use the context menu to “unzoom.” When overlaying multiple histograms or graphs, remember to use SAME. If you forget it, the last drawn object will clear and replace the plot.
Also watch out for object lifetimes affecting drawing. If you create a histogram as a local variable in a function, call Draw(), and then exit the function, the histogram may be destroyed and the canvas left with a dangling reference. For interactive plotting, create the object on the heap and keep a pointer in scope as long as you need it.
For log scales, enabling SetLogy() or SetLogx() on the canvas pad will hide bins with non-positive contents. If your histogram has zeros or negative values, it may disappear partially or entirely on a log axis. In that case, either adjust the content or limit the range to positive bins only.
Compilation and ACLiC Problems
When you move from interpreted macros to compiled ones with ACLiC, new classes of errors appear:
- Compiler errors from missing includes or namespaces.
- Linker errors about undefined references.
- Problems with multiple definitions when recompiling.
First ensure that you include all necessary headers and that you use either explicit namespaces like std::vector or using namespace std; if appropriate. Interpreted ROOT is more forgiving about missing declarations, but a compiled macro must satisfy standard C++ rules.
If ACLiC fails with undefined references, it usually means that you declared a function but did not provide its implementation, or that you forgot to link against an external library. For simple ROOT-only macros, all ROOT libraries are already available, but for custom physics libraries or external code you may need to compile and link them separately.
When recompiling often, old compiled versions can conflict with new code. If ROOT behaves strangely after code changes, remove the .so and .d files generated by ACLiC or use the + and ++ options to force a rebuild. For example, .L myMacro.C++ triggers compilation and link and will rebuild if you changed the file.
Strategies for Diagnosing ROOT Problems
Many of the errors discussed above can be diagnosed with a few simple habits:
Use Print() and ls() frequently to inspect files, trees, and histograms. For example, h->Print(); shows key statistics, and file->ls(); lists available objects. The ROOT browser can also help you explore file contents visually.
Check pointer validity before use. A simple if (!ptr) { / report error / } can save a lot of time. Print informative messages that include object names, file names, and branch names so you can see exactly where things go wrong.
Reduce your macro to the smallest piece of code that reproduces the problem. Often the bug becomes obvious when extra logic is removed. Isolate file opening, tree reading, and histogram filling into separate steps and test each step individually.
Finally, when ROOT prints an error or warning prefix such as Error in <ClassName::Method>:, do not ignore it. Note the class and method names they often point directly to the part of the framework that is failing, which helps you map the problem back to your code.
Views: 18
KAHIBARO