Saving a vector of tensors crashes when one of the tensors is undefiend

I have an application where I use undefined tensors for a zero tensor of any size. This is done to avoid allocating lots of zeros (and seems reasonable). When I try to save a vector with an undefined tensor, the save routine crashes; e.g.

#include <filesystem>
#include <torch/torch.h>

int main() {
    //
    // fs
    namespace fs = std::filesystem;
    //
    // vec_ten_in
    std::vector<at::Tensor> vec_ten_in;
    vec_ten_in.push_back( torch::tensor( {1, 2} ) );
    vec_ten_in.push_back( at::Tensor() );
    //
    // file_name
    fs::path     dir      = fs::temp_directory_path();
    std::string  file_name = (dir / "temp.binary").string();
    torch::save(vec_ten_in, file_name);
    //
    return 0;
}

Can you post the error message please?

Can you run it under a debugger - is the cause of the error an attempt to read unallocated memory?

If, as I suspect, you are crashing on accessing unallocated memory then the solution is very C++ - ish: allocate all the variables - Tensors in this case - that you are trying to use.

@emerth I see your point. This is not a crash but rather libtorch has recognized that the tensor is ‘undefined’; i.e., defined() is false, and refuses to run save for such a tensor.

Here is the error message

pytorch>./main
terminate called after throwing an instance of 'c10::NotImplementedError'
  what():  Cannot access storage of UndefinedTensorImpl
Exception raised from throw_storage_access_error at /pytorch/c10/core/TensorImpl.cpp:298 (most recent call first):
frame #0: c10::Error::Error(c10::SourceLocation, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) + 0x9d (0x7f8072253a9d in /home/bradbell/prefix/venv/lib/python3.14/site-packages/torch/lib/libc10.so)
frame #1: <unknown function> + 0x32701 (0x7f80721e0701 in /home/bradbell/prefix/venv/lib/python3.14/site-packages/torch/lib/libc10.so)
frame #2: <unknown function> + 0x83ce9 (0x7f8072231ce9 in /home/bradbell/prefix/venv/lib/python3.14/site-packages/torch/lib/libc10.so)
frame #3: torch::jit::Pickler::pushStorageOfTensor(at::Tensor const&) + 0x10a (0x7f8063607aba in /home/bradbell/prefix/venv/lib/python3.14/site-packages/torch/lib/libtorch_cpu.so)
frame #4: torch::jit::Pickler::pushLiteralTensor(c10::IValue const&) + 0xe1 (0x7f806360a761 in /home/bradbell/prefix/venv/lib/python3.14/site-packages/torch/lib/libtorch_cpu.so)
frame #5: torch::jit::Pickler::pushIValueImpl(c10::IValue const&) + 0x8d5 (0x7f8063609145 in /home/bradbell/prefix/venv/lib/python3.14/site-packages/torch/lib/libtorch_cpu.so)
frame #6: torch::jit::Pickler::pushIValue(c10::IValue const&) + 0x1c3 (0x7f80636098a3 in /home/bradbell/prefix/venv/lib/python3.14/site-packages/torch/lib/libtorch_cpu.so)
frame #7: torch::jit::ScriptModuleSerializer::writeArchive(c10::IValue const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool, bool) + 0x441 (0x7f8063a9ffb1 in /home/bradbell/prefix/venv/lib/python3.14/site-packages/torch/lib/libtorch_cpu.so)
frame #8: torch::jit::ScriptModuleSerializer::serialize(torch::jit::Module const&, std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&, bool, bool) + 0x121 (0x7f8063aa6fa1 in /home/bradbell/prefix/venv/lib/python3.14/site-packages/torch/lib/libtorch_cpu.so)
frame #9: torch::jit::ExportModule(torch::jit::Module const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&, bool, bool, bool) + 0x520 (0x7f8063aa7f30 in /home/bradbell/prefix/venv/lib/python3.14/site-packages/torch/lib/libtorch_cpu.so)
frame #10: torch::serialize::OutputArchive::save_to(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) + 0x4e (0x7f8063e046ee in /home/bradbell/prefix/venv/lib/python3.14/site-packages/torch/lib/libtorch_cpu.so)
frame #11: ./main() [0x41073a]
frame #12: ./main() [0x400bd6]
frame #13: <unknown function> + 0x3681 (0x7f805cc0a681 in /lib64/libc.so.6)
frame #14: __libc_start_main + 0x88 (0x7f805cc0a798 in /lib64/libc.so.6)
frame #15: ./main() [0x400925]

Aborted                    (core dumped) ./main

This is the ultimate source of the error:

terminate called after throwing an instance of ‘c10::NotImplementedError’
what(): Cannot access storage of UndefinedTensorImpl

Cannot access storage (meaning memory), and torch (I assume torch, IDK what library namespace “c10” belongs to but from context it seems to be internal to torch) throws an exception. The exception is never caught, resulting in terminate() being called. This is standard C++ and system runtime behaviour. You need to actually allocate your Tensors or catch and handle c10::NotImplementedError in some reasonable manner.

I noted you saying about not allocating Tensors full of zeros - I would follow the rule about writing the code and getting it to work, and only then worrying about optimizing it. Probably allocating/saving the zero valued Tensors is not going to be the most expensive thing your program does.

Note it says storage of UndefinedTensorImpl. If you dig into what is inside each of the elements

vec_ten_in.push_back( torch::tensor( {1, 2} ) );
vec_ten_in.push_back( at::Tensor() );

I bet you will find the first one contains some kind of implementation object, whereas the second contains an instance of UndefinedTensorImpl.

Read the docs about at::Tensor - it is a base class you are not really supposed to be instantiating, it contains no allocated storage.

I think you want to be saying this:

vec_ten_in.push_back( torch::tensor( {1, 2} ) );
vec_ten_in.push_back( torch::tensor( {0, 0} ) );

It seems reasonable to me that, since at::Tensor() is one of libtorch’s at::Tensor constructor’s, that save would handle this case. On the other hand, this is not to hard to get around. I have decided to use the tesor torch::empty( {0} ) in its place (which works with torch::save).