problem
When restoring a KVM virtual machine using the CloudStack Veeam integration, the restore fails if the original template from which the VM was deployed has already been deleted from CloudStack.
The VM backup contains the complete root disk and the VM configuration, so the original template image should not be required to restore the VM.
However, the exported/restored VM metadata still references the original CloudStack template ID.
Example from the restore metadata:
<TemplateId>9c12bd7a-3a78-42dc-9bc2-20939014640f</TemplateId>
<TemplateName>9c12bd7a-3a78-42dc-9bc2-20939014640f</TemplateName>
<OriginalTemplateId>9c12bd7a-3a78-42dc-9bc2-20939014640f</OriginalTemplateId>
<OriginalTemplateName>9c12bd7a-3a78-42dc-9bc2-20939014640f</OriginalTemplateName>
The root disk section also contains the same template reference:
<rasd:Template>9c12bd7a-3a78-42dc-9bc2-20939014640f</rasd:Template>
If this template no longer exists in CloudStack, the VM cannot be restored.
NPE trace:
2026-10-01 14:19:00,743 ERROR [c.c.v.UserVmManagerImpl] (qtp1646029317-189:[ctx-780ca248, ctx-a2091f5e]) (logid:) error during resource reservation and allocation java.lang.NullPointerException: Cannot invoke "java.lang.Long.longValue()" because the return value of "com.cloud.storage.VMTemplateVO.getSize()" is null at com.cloud.vm.UserVmManagerImpl.validateRootDiskResize(UserVmManagerImpl.java:5363) at com.cloud.vm.UserVmManagerImpl.commitUserVm(UserVmManagerImpl.java:5102) at com.cloud.vm.UserVmManagerImpl.commitUserVm(UserVmManagerImpl.java:5340) at com.cloud.vm.UserVmManagerImpl.getUncheckedUserVmResource(UserVmManagerImpl.java:4829) at com.cloud.vm.UserVmManagerImpl.getCheckedUserVmResource(UserVmManagerImpl.java:4489) at com.cloud.vm.UserVmManagerImpl.createVirtualMachine(UserVmManagerImpl.java:4460) at com.cloud.vm.UserVmManagerImpl.createAdvancedVirtualMachine(UserVmManagerImpl.java:4232) at com.cloud.vm.UserVmManagerImpl.createVirtualMachine(UserVmManagerImpl.java:6842) at com.cloud.vm.UserVmManagerImpl.createVirtualMachine(UserVmManagerImpl.java:6763) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) at jdk.proxy3/jdk.proxy3.$Proxy159.createVirtualMachine(Unknown Source) at org.apache.cloudstack.veeam.adapter.ServerAdapter.lambda$createVmWithForRestoreIfNeeded$1(ServerAdapter.java:733) at com.cloud.utils.db.Transaction.execute(Transaction.java:38) at org.apache.cloudstack.veeam.adapter.ServerAdapter.createVmWithForRestoreIfNeeded(ServerAdapter.java:725) at org.apache.cloudstack.veeam.adapter.ServerAdapter.createInstance(ServerAdapter.java:825) at org.apache.cloudstack.veeam.adapter.ServerAdapter.createInstance(ServerAdapter.java:1375) at org.apache.cloudstack.veeam.adapter.ServerAdapter$$FastClassBySpringCGLIB$$89e9387c.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) at org.apache.cloudstack.veeam.adapter.ApiAccessInterceptor.invoke(ApiAccessInterceptor.java:63) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) at org.apache.cloudstack.veeam.adapter.ServerAdapter$$EnhancerBySpringCGLIB$$153c7ba4.createInstance(<generated>) at org.apache.cloudstack.veeam.api.VmsRouteHandler.handlePost(VmsRouteHandler.java:263) at org.apache.cloudstack.veeam.api.VmsRouteHandler.handle(VmsRouteHandler.java:82) at org.apache.cloudstack.veeam.VeeamControlServlet.service(VeeamControlServlet.java:79) at javax.servlet.http.HttpServlet.service(HttpServlet.java:750) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799) at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1656) at org.apache.cloudstack.veeam.filter.BearerOrBasicAuthFilter.doFilter(BearerOrBasicAuthFilter.java:79) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626) at org.apache.cloudstack.veeam.filter.AllowedClientCidrsFilter.doFilter(AllowedClientCidrsFilter.java:74) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:552) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:59) at org.eclipse.jetty.server.handler.RequestLogHandler.handle(RequestLogHandler.java:54) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.Server.handle(Server.java:516) at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487) at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:555) at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:410) at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:164) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131) at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883) at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034) at java.base/java.lang.Thread.run(Thread.java:840)
versions
Ubuntu 24.04 KVM Hypervisors
Ubuntu 24.04 Management server
Cloudstack: 4.23.0.0
The steps to reproduce the bug
- Create a template in CloudStack.
- Deploy a VM from that template.
- Back up the VM using the CloudStack/Veeam integration.
- Verify that the VM backup is successful.
- Delete the original template from CloudStack.
- Attempt to restore the previously backed-up VM.
- The restore fails because the original template referenced by the VM metadata is no longer available.
What to do about it?
The restore process requires the original template referenced by TemplateId / OriginalTemplateId to still exist.
If the template has been deleted, the VM restore fails even though the backup contains the VM root disk.
A VM backup should be independently restorable even if the original template has been deleted.
During restore, the template reference should preferably be treated as provenance/metadata rather than as a mandatory dependency.
Possible behavior could be:
if original template exists:
restore VM and preserve the template relationship
if original template does not exist:
restore VM from the backed-up root disk
mark original template as unavailable / null / deleted
The existence of the original template should not prevent restoration of a VM whose root disk is fully contained in the backup. Deleting the original template does not normally make an already deployed VM unusable.
Therefore, a VM-level backup should ideally not introduce a stronger dependency on the original template than the running CloudStack VM itself has.
problem
When restoring a KVM virtual machine using the CloudStack Veeam integration, the restore fails if the original template from which the VM was deployed has already been deleted from CloudStack.
The VM backup contains the complete root disk and the VM configuration, so the original template image should not be required to restore the VM.
However, the exported/restored VM metadata still references the original CloudStack template ID.
Example from the restore metadata:
If this template no longer exists in CloudStack, the VM cannot be restored.
NPE trace:
2026-10-01 14:19:00,743 ERROR [c.c.v.UserVmManagerImpl] (qtp1646029317-189:[ctx-780ca248, ctx-a2091f5e]) (logid:) error during resource reservation and allocation java.lang.NullPointerException: Cannot invoke "java.lang.Long.longValue()" because the return value of "com.cloud.storage.VMTemplateVO.getSize()" is null at com.cloud.vm.UserVmManagerImpl.validateRootDiskResize(UserVmManagerImpl.java:5363) at com.cloud.vm.UserVmManagerImpl.commitUserVm(UserVmManagerImpl.java:5102) at com.cloud.vm.UserVmManagerImpl.commitUserVm(UserVmManagerImpl.java:5340) at com.cloud.vm.UserVmManagerImpl.getUncheckedUserVmResource(UserVmManagerImpl.java:4829) at com.cloud.vm.UserVmManagerImpl.getCheckedUserVmResource(UserVmManagerImpl.java:4489) at com.cloud.vm.UserVmManagerImpl.createVirtualMachine(UserVmManagerImpl.java:4460) at com.cloud.vm.UserVmManagerImpl.createAdvancedVirtualMachine(UserVmManagerImpl.java:4232) at com.cloud.vm.UserVmManagerImpl.createVirtualMachine(UserVmManagerImpl.java:6842) at com.cloud.vm.UserVmManagerImpl.createVirtualMachine(UserVmManagerImpl.java:6763) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) at jdk.proxy3/jdk.proxy3.$Proxy159.createVirtualMachine(Unknown Source) at org.apache.cloudstack.veeam.adapter.ServerAdapter.lambda$createVmWithForRestoreIfNeeded$1(ServerAdapter.java:733) at com.cloud.utils.db.Transaction.execute(Transaction.java:38) at org.apache.cloudstack.veeam.adapter.ServerAdapter.createVmWithForRestoreIfNeeded(ServerAdapter.java:725) at org.apache.cloudstack.veeam.adapter.ServerAdapter.createInstance(ServerAdapter.java:825) at org.apache.cloudstack.veeam.adapter.ServerAdapter.createInstance(ServerAdapter.java:1375) at org.apache.cloudstack.veeam.adapter.ServerAdapter$$FastClassBySpringCGLIB$$89e9387c.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) at org.apache.cloudstack.veeam.adapter.ApiAccessInterceptor.invoke(ApiAccessInterceptor.java:63) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) at org.apache.cloudstack.veeam.adapter.ServerAdapter$$EnhancerBySpringCGLIB$$153c7ba4.createInstance(<generated>) at org.apache.cloudstack.veeam.api.VmsRouteHandler.handlePost(VmsRouteHandler.java:263) at org.apache.cloudstack.veeam.api.VmsRouteHandler.handle(VmsRouteHandler.java:82) at org.apache.cloudstack.veeam.VeeamControlServlet.service(VeeamControlServlet.java:79) at javax.servlet.http.HttpServlet.service(HttpServlet.java:750) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799) at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1656) at org.apache.cloudstack.veeam.filter.BearerOrBasicAuthFilter.doFilter(BearerOrBasicAuthFilter.java:79) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626) at org.apache.cloudstack.veeam.filter.AllowedClientCidrsFilter.doFilter(AllowedClientCidrsFilter.java:74) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:552) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:59) at org.eclipse.jetty.server.handler.RequestLogHandler.handle(RequestLogHandler.java:54) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.Server.handle(Server.java:516) at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487) at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:555) at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:410) at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:164) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131) at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883) at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034) at java.base/java.lang.Thread.run(Thread.java:840)versions
Ubuntu 24.04 KVM Hypervisors
Ubuntu 24.04 Management server
Cloudstack: 4.23.0.0
The steps to reproduce the bug
What to do about it?
The restore process requires the original template referenced by TemplateId / OriginalTemplateId to still exist.
If the template has been deleted, the VM restore fails even though the backup contains the VM root disk.
A VM backup should be independently restorable even if the original template has been deleted.
During restore, the template reference should preferably be treated as provenance/metadata rather than as a mandatory dependency.
Possible behavior could be:
if original template exists:
restore VM and preserve the template relationship
if original template does not exist:
restore VM from the backed-up root disk
mark original template as unavailable / null / deleted
The existence of the original template should not prevent restoration of a VM whose root disk is fully contained in the backup. Deleting the original template does not normally make an already deployed VM unusable.
Therefore, a VM-level backup should ideally not introduce a stronger dependency on the original template than the running CloudStack VM itself has.