diff --git a/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs b/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs
index 38942f7..49cdd28 100644
--- a/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs
+++ b/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs
@@ -6,6 +6,7 @@ using Phantom.Agent.Minecraft.Properties;
 using Phantom.Agent.Minecraft.Server;
 using Phantom.Agent.Rpc;
 using Phantom.Agent.Services.Backups;
+using Phantom.Common.Data;
 using Phantom.Common.Data.Instance;
 using Phantom.Common.Data.Minecraft;
 using Phantom.Common.Data.Replies;
@@ -48,10 +49,10 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
 
 		this.instanceServices = new InstanceServices(init.ControllerConnection, init.BackupManager, launchServices);
 		
-		ReceiveAndReply<ConfigureInstanceCommand, InstanceActionResult<ConfigureInstanceResult>>(ConfigureInstance);
-		ReceiveAndReply<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance);
-		ReceiveAndReply<StopInstanceCommand, InstanceActionResult<StopInstanceResult>>(StopInstance);
-		ReceiveAsyncAndReply<SendCommandToInstanceCommand, InstanceActionResult<SendCommandToInstanceResult>>(SendCommandToInstance);
+		ReceiveAndReply<ConfigureInstanceCommand, Result<ConfigureInstanceResult, InstanceActionFailure>>(ConfigureInstance);
+		ReceiveAndReply<LaunchInstanceCommand, Result<LaunchInstanceResult, InstanceActionFailure>>(LaunchInstance);
+		ReceiveAndReply<StopInstanceCommand, Result<StopInstanceResult, InstanceActionFailure>>(StopInstance);
+		ReceiveAsyncAndReply<SendCommandToInstanceCommand, Result<SendCommandToInstanceResult, InstanceActionFailure>>(SendCommandToInstance);
 		ReceiveAsync<ShutdownCommand>(Shutdown);
 	}
 
@@ -64,17 +65,17 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
 	
 	public interface ICommand {}
 	
-	public sealed record ConfigureInstanceCommand(Guid InstanceGuid, InstanceConfiguration Configuration, InstanceLaunchProperties LaunchProperties, bool LaunchNow, bool AlwaysReportStatus) : ICommand, ICanReply<InstanceActionResult<ConfigureInstanceResult>>;
+	public sealed record ConfigureInstanceCommand(Guid InstanceGuid, InstanceConfiguration Configuration, InstanceLaunchProperties LaunchProperties, bool LaunchNow, bool AlwaysReportStatus) : ICommand, ICanReply<Result<ConfigureInstanceResult, InstanceActionFailure>>;
 	
-	public sealed record LaunchInstanceCommand(Guid InstanceGuid) : ICommand, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
+	public sealed record LaunchInstanceCommand(Guid InstanceGuid) : ICommand, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
 	
-	public sealed record StopInstanceCommand(Guid InstanceGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<InstanceActionResult<StopInstanceResult>>;
+	public sealed record StopInstanceCommand(Guid InstanceGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<Result<StopInstanceResult, InstanceActionFailure>>;
 	
-	public sealed record SendCommandToInstanceCommand(Guid InstanceGuid, string Command) : ICommand, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
+	public sealed record SendCommandToInstanceCommand(Guid InstanceGuid, string Command) : ICommand, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
 	
 	public sealed record ShutdownCommand : ICommand;
 
-	private InstanceActionResult<ConfigureInstanceResult> ConfigureInstance(ConfigureInstanceCommand command) {
+	private Result<ConfigureInstanceResult, InstanceActionFailure> ConfigureInstance(ConfigureInstanceCommand command) {
 		var instanceGuid = command.InstanceGuid;
 		var configuration = command.Configuration;
 
@@ -129,64 +130,64 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
 			LaunchInstance(new LaunchInstanceCommand(instanceGuid));
 		}
 
-		return InstanceActionResult.Concrete(ConfigureInstanceResult.Success);
+		return ConfigureInstanceResult.Success;
 	}
 
-	private InstanceActionResult<LaunchInstanceResult> LaunchInstance(LaunchInstanceCommand command) {
+	private Result<LaunchInstanceResult, InstanceActionFailure> LaunchInstance(LaunchInstanceCommand command) {
 		var instanceGuid = command.InstanceGuid;
 		if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
-			return InstanceActionResult.General<LaunchInstanceResult>(InstanceActionGeneralResult.InstanceDoesNotExist);
+			return InstanceActionFailure.InstanceDoesNotExist;
 		}
 		
 		var ticket = instanceTicketManager.Reserve(instanceInfo.Configuration);
 		if (!ticket) {
-			return InstanceActionResult.Concrete(ticket.Error);
+			return ticket.Error;
 		}
 
 		if (agentState.InstancesByGuid.TryGetValue(instanceGuid, out var instance)) {
 			var status = instance.Status;
 			if (status.IsRunning()) {
-				return InstanceActionResult.Concrete(LaunchInstanceResult.InstanceAlreadyRunning);
+				return LaunchInstanceResult.InstanceAlreadyRunning;
 			}
 			else if (status.IsLaunching()) {
-				return InstanceActionResult.Concrete(LaunchInstanceResult.InstanceAlreadyLaunching);
+				return LaunchInstanceResult.InstanceAlreadyLaunching;
 			}
 		}
 		
 		instanceInfo.Actor.Tell(new InstanceActor.LaunchInstanceCommand(instanceInfo.Configuration, instanceInfo.Launcher, ticket.Value, IsRestarting: false));
-		return InstanceActionResult.Concrete(LaunchInstanceResult.LaunchInitiated);
+		return LaunchInstanceResult.LaunchInitiated;
 	}
 
-	private InstanceActionResult<StopInstanceResult> StopInstance(StopInstanceCommand command) {
+	private Result<StopInstanceResult, InstanceActionFailure> StopInstance(StopInstanceCommand command) {
 		var instanceGuid = command.InstanceGuid;
 		if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
-			return InstanceActionResult.General<StopInstanceResult>(InstanceActionGeneralResult.InstanceDoesNotExist);
+			return InstanceActionFailure.InstanceDoesNotExist;
 		}
         
 		if (agentState.InstancesByGuid.TryGetValue(instanceGuid, out var instance)) {
 			var status = instance.Status;
 			if (status.IsStopping()) {
-				return InstanceActionResult.Concrete(StopInstanceResult.InstanceAlreadyStopping);
+				return StopInstanceResult.InstanceAlreadyStopping;
 			}
 			else if (!status.CanStop()) {
-				return InstanceActionResult.Concrete(StopInstanceResult.InstanceAlreadyStopped);
+				return StopInstanceResult.InstanceAlreadyStopped;
 			}
 		}
 			
 		instanceInfo.Actor.Tell(new InstanceActor.StopInstanceCommand(command.StopStrategy));
-		return InstanceActionResult.Concrete(StopInstanceResult.StopInitiated);
+		return StopInstanceResult.StopInitiated;
 	}
 
-	private async Task<InstanceActionResult<SendCommandToInstanceResult>> SendCommandToInstance(SendCommandToInstanceCommand command) {
+	private async Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> SendCommandToInstance(SendCommandToInstanceCommand command) {
 		var instanceGuid = command.InstanceGuid;
 		if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
-			return InstanceActionResult.General<SendCommandToInstanceResult>(InstanceActionGeneralResult.InstanceDoesNotExist);
+			return InstanceActionFailure.InstanceDoesNotExist;
 		}
 
 		try {
-			return InstanceActionResult.Concrete(await instanceInfo.Actor.Request(new InstanceActor.SendCommandToInstanceCommand(command.Command), shutdownCancellationToken));
+			return await instanceInfo.Actor.Request(new InstanceActor.SendCommandToInstanceCommand(command.Command), shutdownCancellationToken);
 		} catch (OperationCanceledException) {
-			return InstanceActionResult.General<SendCommandToInstanceResult>(InstanceActionGeneralResult.AgentShuttingDown);
+			return InstanceActionFailure.AgentShuttingDown;
 		}
 	}
 
diff --git a/Agent/Phantom.Agent.Services/Rpc/ControllerMessageHandlerActor.cs b/Agent/Phantom.Agent.Services/Rpc/ControllerMessageHandlerActor.cs
index c89b893..8e1c439 100644
--- a/Agent/Phantom.Agent.Services/Rpc/ControllerMessageHandlerActor.cs
+++ b/Agent/Phantom.Agent.Services/Rpc/ControllerMessageHandlerActor.cs
@@ -1,4 +1,5 @@
 using Phantom.Agent.Services.Instances;
+using Phantom.Common.Data;
 using Phantom.Common.Data.Instance;
 using Phantom.Common.Data.Replies;
 using Phantom.Common.Messages.Agent;
@@ -32,10 +33,10 @@ public sealed class ControllerMessageHandlerActor : ReceiveActor<IMessageToAgent
 		
 		ReceiveAsync<RegisterAgentSuccessMessage>(HandleRegisterAgentSuccess);
 		Receive<RegisterAgentFailureMessage>(HandleRegisterAgentFailure);
-		ReceiveAndReplyLater<ConfigureInstanceMessage, InstanceActionResult<ConfigureInstanceResult>>(HandleConfigureInstance);
-		ReceiveAndReplyLater<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(HandleLaunchInstance);
-		ReceiveAndReplyLater<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(HandleStopInstance);
-		ReceiveAndReplyLater<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(HandleSendCommandToInstance);
+		ReceiveAndReplyLater<ConfigureInstanceMessage, Result<ConfigureInstanceResult, InstanceActionFailure>>(HandleConfigureInstance);
+		ReceiveAndReplyLater<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(HandleLaunchInstance);
+		ReceiveAndReplyLater<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(HandleStopInstance);
+		ReceiveAndReplyLater<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(HandleSendCommandToInstance);
 		Receive<ReplyMessage>(HandleReply);
 	}
 
@@ -74,23 +75,23 @@ public sealed class ControllerMessageHandlerActor : ReceiveActor<IMessageToAgent
 		Environment.Exit(1);
 	}
 	
-	private Task<InstanceActionResult<ConfigureInstanceResult>> HandleConfigureInstance(ConfigureInstanceMessage message, bool alwaysReportStatus) {
+	private Task<Result<ConfigureInstanceResult, InstanceActionFailure>> HandleConfigureInstance(ConfigureInstanceMessage message, bool alwaysReportStatus) {
 		return agent.InstanceManager.Request(new InstanceManagerActor.ConfigureInstanceCommand(message.InstanceGuid, message.Configuration, message.LaunchProperties, message.LaunchNow, alwaysReportStatus));
 	}
 	
-	private async Task<InstanceActionResult<ConfigureInstanceResult>> HandleConfigureInstance(ConfigureInstanceMessage message) {
+	private async Task<Result<ConfigureInstanceResult, InstanceActionFailure>> HandleConfigureInstance(ConfigureInstanceMessage message) {
 		return await HandleConfigureInstance(message, alwaysReportStatus: false);
 	}
 
-	private async Task<InstanceActionResult<LaunchInstanceResult>> HandleLaunchInstance(LaunchInstanceMessage message) {
+	private async Task<Result<LaunchInstanceResult, InstanceActionFailure>> HandleLaunchInstance(LaunchInstanceMessage message) {
 		return await agent.InstanceManager.Request(new InstanceManagerActor.LaunchInstanceCommand(message.InstanceGuid));
 	}
 
-	private async Task<InstanceActionResult<StopInstanceResult>> HandleStopInstance(StopInstanceMessage message) {
+	private async Task<Result<StopInstanceResult, InstanceActionFailure>> HandleStopInstance(StopInstanceMessage message) {
 		return await agent.InstanceManager.Request(new InstanceManagerActor.StopInstanceCommand(message.InstanceGuid, message.StopStrategy));
 	}
 
-	private async Task<InstanceActionResult<SendCommandToInstanceResult>> HandleSendCommandToInstance(SendCommandToInstanceMessage message) {
+	private async Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> HandleSendCommandToInstance(SendCommandToInstanceMessage message) {
 		return await agent.InstanceManager.Request(new InstanceManagerActor.SendCommandToInstanceCommand(message.InstanceGuid, message.Command));
 	}
 
diff --git a/Common/Phantom.Common.Data/Replies/InstanceActionFailure.cs b/Common/Phantom.Common.Data/Replies/InstanceActionFailure.cs
new file mode 100644
index 0000000..4b57fda
--- /dev/null
+++ b/Common/Phantom.Common.Data/Replies/InstanceActionFailure.cs
@@ -0,0 +1,20 @@
+namespace Phantom.Common.Data.Replies;
+
+public enum InstanceActionFailure : byte {
+	AgentDoesNotExist,
+	AgentShuttingDown,
+	AgentIsNotResponding,
+	InstanceDoesNotExist
+}
+
+public static class InstanceActionFailureExtensions {
+	public static string ToSentence(this InstanceActionFailure failure) {
+		return failure switch {
+			InstanceActionFailure.AgentDoesNotExist    => "Agent does not exist.",
+			InstanceActionFailure.AgentShuttingDown    => "Agent is shutting down.",
+			InstanceActionFailure.AgentIsNotResponding => "Agent is not responding.",
+			InstanceActionFailure.InstanceDoesNotExist => "Instance does not exist.",
+			_                                          => "Unknown error."
+		};
+	}
+}
diff --git a/Common/Phantom.Common.Data/Replies/InstanceActionGeneralResult.cs b/Common/Phantom.Common.Data/Replies/InstanceActionGeneralResult.cs
deleted file mode 100644
index 2cd08b5..0000000
--- a/Common/Phantom.Common.Data/Replies/InstanceActionGeneralResult.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Phantom.Common.Data.Replies;
-
-public enum InstanceActionGeneralResult : byte {
-	None,
-	AgentDoesNotExist,
-	AgentShuttingDown,
-	AgentIsNotResponding,
-	InstanceDoesNotExist
-}
diff --git a/Common/Phantom.Common.Data/Replies/InstanceActionResult.cs b/Common/Phantom.Common.Data/Replies/InstanceActionResult.cs
deleted file mode 100644
index 2ac7b9c..0000000
--- a/Common/Phantom.Common.Data/Replies/InstanceActionResult.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using MemoryPack;
-
-namespace Phantom.Common.Data.Replies;
-
-[MemoryPackable(GenerateType.VersionTolerant)]
-public sealed partial record InstanceActionResult<T>(
-	[property: MemoryPackOrder(0)] InstanceActionGeneralResult GeneralResult,
-	[property: MemoryPackOrder(1)] T? ConcreteResult
-) {
-	public bool Is(T? concreteResult) {
-		return GeneralResult == InstanceActionGeneralResult.None && EqualityComparer<T>.Default.Equals(ConcreteResult, concreteResult);
-	}
-
-	public InstanceActionResult<T2> Map<T2>(Func<T, T2> mapper) {
-		return new InstanceActionResult<T2>(GeneralResult, ConcreteResult is not null ? mapper(ConcreteResult) : default);
-	}
-
-	public string ToSentence(Func<T, string> concreteResultToSentence) {
-		return GeneralResult switch {
-			InstanceActionGeneralResult.None                 => concreteResultToSentence(ConcreteResult!),
-			InstanceActionGeneralResult.AgentDoesNotExist    => "Agent does not exist.",
-			InstanceActionGeneralResult.AgentShuttingDown    => "Agent is shutting down.",
-			InstanceActionGeneralResult.AgentIsNotResponding => "Agent is not responding.",
-			InstanceActionGeneralResult.InstanceDoesNotExist => "Instance does not exist.",
-			_                                                => "Unknown result."
-		};
-	}
-}
-
-public static class InstanceActionResult {
-	public static InstanceActionResult<T> General<T>(InstanceActionGeneralResult generalResult) {
-		return new InstanceActionResult<T>(generalResult, default);
-	}
-
-	public static InstanceActionResult<T> Concrete<T>(T? concreteResult) {
-		return new InstanceActionResult<T>(InstanceActionGeneralResult.None, concreteResult);
-	}
-
-	public static InstanceActionResult<T> DidNotReplyIfNull<T>(this InstanceActionResult<T>? result) {
-		return result ?? General<T>(InstanceActionGeneralResult.AgentIsNotResponding);
-	}
-}
diff --git a/Common/Phantom.Common.Data/Result.cs b/Common/Phantom.Common.Data/Result.cs
index c448812..5fb88f8 100644
--- a/Common/Phantom.Common.Data/Result.cs
+++ b/Common/Phantom.Common.Data/Result.cs
@@ -29,6 +29,14 @@ public sealed partial class Result<TValue, TError> {
 		this.error = error;
 	}
 
+	public bool Is(TValue expectedValue) {
+		return hasValue && EqualityComparer<TValue>.Default.Equals(value, expectedValue);
+	}
+
+	public TOutput Map<TOutput>(Func<TValue, TOutput> valueConverter, Func<TError, TOutput> errorConverter) {
+		return hasValue ? valueConverter(value!) : errorConverter(error!);
+	}
+
 	public static implicit operator Result<TValue, TError>(TValue value) {
 		return new Result<TValue, TError>(hasValue: true, value, default);
 	}
diff --git a/Common/Phantom.Common.Messages.Agent/AgentMessageRegistries.cs b/Common/Phantom.Common.Messages.Agent/AgentMessageRegistries.cs
index c93cb57..c3b9c3a 100644
--- a/Common/Phantom.Common.Messages.Agent/AgentMessageRegistries.cs
+++ b/Common/Phantom.Common.Messages.Agent/AgentMessageRegistries.cs
@@ -1,4 +1,5 @@
-using Phantom.Common.Data.Replies;
+using Phantom.Common.Data;
+using Phantom.Common.Data.Replies;
 using Phantom.Common.Messages.Agent.BiDirectional;
 using Phantom.Common.Messages.Agent.ToAgent;
 using Phantom.Common.Messages.Agent.ToController;
@@ -16,10 +17,10 @@ public static class AgentMessageRegistries {
 	static AgentMessageRegistries() {
 		ToAgent.Add<RegisterAgentSuccessMessage>(0);
 		ToAgent.Add<RegisterAgentFailureMessage>(1);
-		ToAgent.Add<ConfigureInstanceMessage, InstanceActionResult<ConfigureInstanceResult>>(2);
-		ToAgent.Add<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(3);
-		ToAgent.Add<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(4);
-		ToAgent.Add<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(5);
+		ToAgent.Add<ConfigureInstanceMessage, Result<ConfigureInstanceResult, InstanceActionFailure>>(2);
+		ToAgent.Add<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(3);
+		ToAgent.Add<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(4);
+		ToAgent.Add<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(5);
 		ToAgent.Add<ReplyMessage>(127);
 		
 		ToController.Add<RegisterAgentMessage>(0);
diff --git a/Common/Phantom.Common.Messages.Agent/ToAgent/ConfigureInstanceMessage.cs b/Common/Phantom.Common.Messages.Agent/ToAgent/ConfigureInstanceMessage.cs
index 8d4e69f..9472572 100644
--- a/Common/Phantom.Common.Messages.Agent/ToAgent/ConfigureInstanceMessage.cs
+++ b/Common/Phantom.Common.Messages.Agent/ToAgent/ConfigureInstanceMessage.cs
@@ -1,4 +1,5 @@
 using MemoryPack;
+using Phantom.Common.Data;
 using Phantom.Common.Data.Instance;
 using Phantom.Common.Data.Replies;
 using Phantom.Utils.Actor;
@@ -11,4 +12,4 @@ public sealed partial record ConfigureInstanceMessage(
 	[property: MemoryPackOrder(1)] InstanceConfiguration Configuration,
 	[property: MemoryPackOrder(2)] InstanceLaunchProperties LaunchProperties,
 	[property: MemoryPackOrder(3)] bool LaunchNow = false
-) : IMessageToAgent, ICanReply<InstanceActionResult<ConfigureInstanceResult>>;
+) : IMessageToAgent, ICanReply<Result<ConfigureInstanceResult, InstanceActionFailure>>;
diff --git a/Common/Phantom.Common.Messages.Agent/ToAgent/LaunchInstanceMessage.cs b/Common/Phantom.Common.Messages.Agent/ToAgent/LaunchInstanceMessage.cs
index 072cb1b..59f958b 100644
--- a/Common/Phantom.Common.Messages.Agent/ToAgent/LaunchInstanceMessage.cs
+++ b/Common/Phantom.Common.Messages.Agent/ToAgent/LaunchInstanceMessage.cs
@@ -1,4 +1,5 @@
 using MemoryPack;
+using Phantom.Common.Data;
 using Phantom.Common.Data.Replies;
 using Phantom.Utils.Actor;
 
@@ -7,4 +8,4 @@ namespace Phantom.Common.Messages.Agent.ToAgent;
 [MemoryPackable(GenerateType.VersionTolerant)]
 public sealed partial record LaunchInstanceMessage(
 	[property: MemoryPackOrder(0)] Guid InstanceGuid
-) : IMessageToAgent, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
+) : IMessageToAgent, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
diff --git a/Common/Phantom.Common.Messages.Agent/ToAgent/SendCommandToInstanceMessage.cs b/Common/Phantom.Common.Messages.Agent/ToAgent/SendCommandToInstanceMessage.cs
index 26fccef..7055e62 100644
--- a/Common/Phantom.Common.Messages.Agent/ToAgent/SendCommandToInstanceMessage.cs
+++ b/Common/Phantom.Common.Messages.Agent/ToAgent/SendCommandToInstanceMessage.cs
@@ -1,4 +1,5 @@
 using MemoryPack;
+using Phantom.Common.Data;
 using Phantom.Common.Data.Replies;
 using Phantom.Utils.Actor;
 
@@ -8,4 +9,4 @@ namespace Phantom.Common.Messages.Agent.ToAgent;
 public sealed partial record SendCommandToInstanceMessage(
 	[property: MemoryPackOrder(0)] Guid InstanceGuid,
 	[property: MemoryPackOrder(1)] string Command
-) : IMessageToAgent, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
+) : IMessageToAgent, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
diff --git a/Common/Phantom.Common.Messages.Agent/ToAgent/StopInstanceMessage.cs b/Common/Phantom.Common.Messages.Agent/ToAgent/StopInstanceMessage.cs
index 55b1e20..5f74857 100644
--- a/Common/Phantom.Common.Messages.Agent/ToAgent/StopInstanceMessage.cs
+++ b/Common/Phantom.Common.Messages.Agent/ToAgent/StopInstanceMessage.cs
@@ -1,4 +1,5 @@
 using MemoryPack;
+using Phantom.Common.Data;
 using Phantom.Common.Data.Minecraft;
 using Phantom.Common.Data.Replies;
 using Phantom.Utils.Actor;
@@ -9,4 +10,4 @@ namespace Phantom.Common.Messages.Agent.ToAgent;
 public sealed partial record StopInstanceMessage(
 	[property: MemoryPackOrder(0)] Guid InstanceGuid,
 	[property: MemoryPackOrder(1)] MinecraftStopStrategy StopStrategy
-) : IMessageToAgent, ICanReply<InstanceActionResult<StopInstanceResult>>;
+) : IMessageToAgent, ICanReply<Result<StopInstanceResult, InstanceActionFailure>>;
diff --git a/Common/Phantom.Common.Messages.Web/ToController/CreateOrUpdateInstanceMessage.cs b/Common/Phantom.Common.Messages.Web/ToController/CreateOrUpdateInstanceMessage.cs
index 8150fe1..a35cd78 100644
--- a/Common/Phantom.Common.Messages.Web/ToController/CreateOrUpdateInstanceMessage.cs
+++ b/Common/Phantom.Common.Messages.Web/ToController/CreateOrUpdateInstanceMessage.cs
@@ -1,4 +1,5 @@
 using MemoryPack;
+using Phantom.Common.Data;
 using Phantom.Common.Data.Instance;
 using Phantom.Common.Data.Replies;
 using Phantom.Common.Data.Web.Instance;
@@ -11,4 +12,4 @@ public sealed partial record CreateOrUpdateInstanceMessage(
 	[property: MemoryPackOrder(0)] Guid LoggedInUserGuid,
 	[property: MemoryPackOrder(1)] Guid InstanceGuid,
 	[property: MemoryPackOrder(2)] InstanceConfiguration Configuration
-) : IMessageToController, ICanReply<InstanceActionResult<CreateOrUpdateInstanceResult>>;
+) : IMessageToController, ICanReply<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>;
diff --git a/Common/Phantom.Common.Messages.Web/ToController/LaunchInstanceMessage.cs b/Common/Phantom.Common.Messages.Web/ToController/LaunchInstanceMessage.cs
index deed50b..eebcdfa 100644
--- a/Common/Phantom.Common.Messages.Web/ToController/LaunchInstanceMessage.cs
+++ b/Common/Phantom.Common.Messages.Web/ToController/LaunchInstanceMessage.cs
@@ -1,4 +1,5 @@
 using MemoryPack;
+using Phantom.Common.Data;
 using Phantom.Common.Data.Replies;
 using Phantom.Utils.Actor;
 
@@ -9,4 +10,4 @@ public sealed partial record LaunchInstanceMessage(
 	[property: MemoryPackOrder(0)] Guid LoggedInUserGuid,
 	[property: MemoryPackOrder(1)] Guid AgentGuid,
 	[property: MemoryPackOrder(2)] Guid InstanceGuid
-) : IMessageToController, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
+) : IMessageToController, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
diff --git a/Common/Phantom.Common.Messages.Web/ToController/SendCommandToInstanceMessage.cs b/Common/Phantom.Common.Messages.Web/ToController/SendCommandToInstanceMessage.cs
index 490aee9..485cc6f 100644
--- a/Common/Phantom.Common.Messages.Web/ToController/SendCommandToInstanceMessage.cs
+++ b/Common/Phantom.Common.Messages.Web/ToController/SendCommandToInstanceMessage.cs
@@ -1,4 +1,5 @@
 using MemoryPack;
+using Phantom.Common.Data;
 using Phantom.Common.Data.Replies;
 using Phantom.Utils.Actor;
 
@@ -10,4 +11,4 @@ public sealed partial record SendCommandToInstanceMessage(
 	[property: MemoryPackOrder(1)] Guid AgentGuid,
 	[property: MemoryPackOrder(2)] Guid InstanceGuid,
 	[property: MemoryPackOrder(3)] string Command
-) : IMessageToController, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
+) : IMessageToController, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
diff --git a/Common/Phantom.Common.Messages.Web/ToController/StopInstanceMessage.cs b/Common/Phantom.Common.Messages.Web/ToController/StopInstanceMessage.cs
index 585c3e9..1f0a94a 100644
--- a/Common/Phantom.Common.Messages.Web/ToController/StopInstanceMessage.cs
+++ b/Common/Phantom.Common.Messages.Web/ToController/StopInstanceMessage.cs
@@ -1,4 +1,5 @@
 using MemoryPack;
+using Phantom.Common.Data;
 using Phantom.Common.Data.Minecraft;
 using Phantom.Common.Data.Replies;
 using Phantom.Utils.Actor;
@@ -11,4 +12,4 @@ public sealed partial record StopInstanceMessage(
 	[property: MemoryPackOrder(1)] Guid AgentGuid,
 	[property: MemoryPackOrder(2)] Guid InstanceGuid,
 	[property: MemoryPackOrder(3)] MinecraftStopStrategy StopStrategy
-) : IMessageToController, ICanReply<InstanceActionResult<StopInstanceResult>>;
+) : IMessageToController, ICanReply<Result<StopInstanceResult, InstanceActionFailure>>;
diff --git a/Common/Phantom.Common.Messages.Web/WebMessageRegistries.cs b/Common/Phantom.Common.Messages.Web/WebMessageRegistries.cs
index f1aa4b5..ba0b45c 100644
--- a/Common/Phantom.Common.Messages.Web/WebMessageRegistries.cs
+++ b/Common/Phantom.Common.Messages.Web/WebMessageRegistries.cs
@@ -34,10 +34,10 @@ public static class WebMessageRegistries {
 		ToController.Add<GetRolesMessage, ImmutableArray<RoleInfo>>(9);
 		ToController.Add<GetUserRolesMessage, ImmutableDictionary<Guid, ImmutableArray<Guid>>>(10);
 		ToController.Add<ChangeUserRolesMessage, ChangeUserRolesResult>(11);
-		ToController.Add<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(12);
-		ToController.Add<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(13);
-		ToController.Add<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(14);
-		ToController.Add<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(15);
+		ToController.Add<CreateOrUpdateInstanceMessage, Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(12);
+		ToController.Add<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(13);
+		ToController.Add<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(14);
+		ToController.Add<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(15);
 		ToController.Add<GetMinecraftVersionsMessage, ImmutableArray<MinecraftVersion>>(16);
 		ToController.Add<GetAgentJavaRuntimesMessage, ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>>(17);
 		ToController.Add<GetAuditLogMessage, ImmutableArray<AuditLogItem>>(18);
diff --git a/Controller/Phantom.Controller.Services/Agents/AgentActor.cs b/Controller/Phantom.Controller.Services/Agents/AgentActor.cs
index e7984af..fea3764 100644
--- a/Controller/Phantom.Controller.Services/Agents/AgentActor.cs
+++ b/Controller/Phantom.Controller.Services/Agents/AgentActor.cs
@@ -92,11 +92,11 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
 		Receive<NotifyIsAliveCommand>(NotifyIsAlive);
 		Receive<UpdateStatsCommand>(UpdateStats);
 		Receive<UpdateJavaRuntimesCommand>(UpdateJavaRuntimes);
-		ReceiveAndReplyLater<CreateOrUpdateInstanceCommand, InstanceActionResult<CreateOrUpdateInstanceResult>>(CreateOrUpdateInstance);
+		ReceiveAndReplyLater<CreateOrUpdateInstanceCommand, Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(CreateOrUpdateInstance);
 		Receive<UpdateInstanceStatusCommand>(UpdateInstanceStatus);
-		ReceiveAndReplyLater<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance);
-		ReceiveAndReplyLater<StopInstanceCommand, InstanceActionResult<StopInstanceResult>>(StopInstance);
-		ReceiveAndReplyLater<SendCommandToInstanceCommand, InstanceActionResult<SendCommandToInstanceResult>>(SendMinecraftCommand);
+		ReceiveAndReplyLater<LaunchInstanceCommand, Result<LaunchInstanceResult, InstanceActionFailure>>(LaunchInstance);
+		ReceiveAndReplyLater<StopInstanceCommand, Result<StopInstanceResult, InstanceActionFailure>>(StopInstance);
+		ReceiveAndReplyLater<SendCommandToInstanceCommand, Result<SendCommandToInstanceResult, InstanceActionFailure>>(SendMinecraftCommand);
 		Receive<ReceiveInstanceDataCommand>(ReceiveInstanceData);
 	}
 
@@ -144,13 +144,13 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
 		}
 	}
 
-	private Task<InstanceActionResult<TReply>> RequestInstance<TCommand, TReply>(Guid instanceGuid, TCommand command) where TCommand : InstanceActor.ICommand, ICanReply<InstanceActionResult<TReply>> {
+	private Task<Result<TReply, InstanceActionFailure>> RequestInstance<TCommand, TReply>(Guid instanceGuid, TCommand command) where TCommand : InstanceActor.ICommand, ICanReply<Result<TReply, InstanceActionFailure>> {
 		if (instanceActorByGuid.TryGetValue(instanceGuid, out var instance)) {
 			return instance.Request(command, cancellationToken);
 		}
 		else {
 			Logger.Warning("Could not deliver command {CommandType} to instance {InstanceGuid}, instance not found.", command.GetType().Name, instanceGuid);
-			return Task.FromResult(InstanceActionResult.General<TReply>(InstanceActionGeneralResult.InstanceDoesNotExist));
+			return Task.FromResult<Result<TReply, InstanceActionFailure>>(InstanceActionFailure.InstanceDoesNotExist);
 		}
 	}
 
@@ -181,15 +181,15 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
 	
 	public sealed record UpdateJavaRuntimesCommand(ImmutableArray<TaggedJavaRuntime> JavaRuntimes) : ICommand;
 	
-	public sealed record CreateOrUpdateInstanceCommand(Guid AuditLogUserGuid, Guid InstanceGuid, InstanceConfiguration Configuration) : ICommand, ICanReply<InstanceActionResult<CreateOrUpdateInstanceResult>>;
+	public sealed record CreateOrUpdateInstanceCommand(Guid AuditLogUserGuid, Guid InstanceGuid, InstanceConfiguration Configuration) : ICommand, ICanReply<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>;
 	
 	public sealed record UpdateInstanceStatusCommand(Guid InstanceGuid, IInstanceStatus Status) : ICommand;
 
-	public sealed record LaunchInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid) : ICommand, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
+	public sealed record LaunchInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid) : ICommand, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
 	
-	public sealed record StopInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<InstanceActionResult<StopInstanceResult>>;
+	public sealed record StopInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<Result<StopInstanceResult, InstanceActionFailure>>;
 	
-	public sealed record SendCommandToInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid, string Command) : ICommand, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
+	public sealed record SendCommandToInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid, string Command) : ICommand, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
 	
 	public sealed record ReceiveInstanceDataCommand(Instance Instance) : ICommand, IJumpAhead;
 
@@ -270,15 +270,15 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
 		controllerState.UpdateAgentJavaRuntimes(agentGuid, javaRuntimes);
 	}
 	
-	private Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance(CreateOrUpdateInstanceCommand command) {
+	private Task<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>> CreateOrUpdateInstance(CreateOrUpdateInstanceCommand command) {
 		var instanceConfiguration = command.Configuration;
 
 		if (string.IsNullOrWhiteSpace(instanceConfiguration.InstanceName)) {
-			return Task.FromResult(InstanceActionResult.Concrete(CreateOrUpdateInstanceResult.InstanceNameMustNotBeEmpty));
+			return Task.FromResult<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(CreateOrUpdateInstanceResult.InstanceNameMustNotBeEmpty);
 		}
 		
 		if (instanceConfiguration.MemoryAllocation <= RamAllocationUnits.Zero) {
-			return Task.FromResult(InstanceActionResult.Concrete(CreateOrUpdateInstanceResult.InstanceMemoryMustNotBeZero));
+			return Task.FromResult<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(CreateOrUpdateInstanceResult.InstanceMemoryMustNotBeZero);
 		}
 		
 		return minecraftVersions.GetServerExecutableInfo(instanceConfiguration.MinecraftVersion, cancellationToken)
@@ -286,9 +286,9 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
 		                        .Unwrap();
 	}
 
-	private Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance1(FileDownloadInfo? serverExecutableInfo, CreateOrUpdateInstanceCommand command) {
+	private Task<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>> CreateOrUpdateInstance1(FileDownloadInfo? serverExecutableInfo, CreateOrUpdateInstanceCommand command) {
 		if (serverExecutableInfo == null) {
-			return Task.FromResult(InstanceActionResult.Concrete(CreateOrUpdateInstanceResult.MinecraftVersionDownloadInfoNotFound));
+			return Task.FromResult<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(CreateOrUpdateInstanceResult.MinecraftVersionDownloadInfoNotFound);
 		}
 		
 		var instanceConfiguration = command.Configuration;
@@ -304,7 +304,7 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
 		                       .ContinueOnActor(CreateOrUpdateInstance2, configureInstanceCommand);
 	}
 	
-	private InstanceActionResult<CreateOrUpdateInstanceResult> CreateOrUpdateInstance2(InstanceActionResult<ConfigureInstanceResult> result, InstanceActor.ConfigureInstanceCommand command) {
+	private Result<CreateOrUpdateInstanceResult, InstanceActionFailure> CreateOrUpdateInstance2(Result<ConfigureInstanceResult, InstanceActionFailure> result, InstanceActor.ConfigureInstanceCommand command) {
 		var instanceGuid = command.InstanceGuid;
 		var instanceName = command.Configuration.InstanceName;
 		var isCreating = command.IsCreatingInstance;
@@ -312,33 +312,35 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
 		if (result.Is(ConfigureInstanceResult.Success)) {
 			string action = isCreating ? "Added" : "Edited";
 			string relation = isCreating ? "to agent" : "in agent";
+			
 			Logger.Information(action + " instance \"{InstanceName}\" (GUID {InstanceGuid}) " + relation + " \"{AgentName}\".", instanceName, instanceGuid, configuration.AgentName);
+			
+			return CreateOrUpdateInstanceResult.Success;
 		}
 		else {
 			string action = isCreating ? "adding" : "editing";
 			string relation = isCreating ? "to agent" : "in agent";
-			Logger.Information("Failed " + action + " instance \"{InstanceName}\" (GUID {InstanceGuid}) " + relation + " \"{AgentName}\". {ErrorMessage}", instanceName, instanceGuid, configuration.AgentName, result.ToSentence(ConfigureInstanceResultExtensions.ToSentence));
+			string reason = result.Map(ConfigureInstanceResultExtensions.ToSentence, InstanceActionFailureExtensions.ToSentence);
+			
+			Logger.Information("Failed " + action + " instance \"{InstanceName}\" (GUID {InstanceGuid}) " + relation + " \"{AgentName}\". {ErrorMessage}", instanceName, instanceGuid, configuration.AgentName, reason);
+			
+			return CreateOrUpdateInstanceResult.UnknownError;
 		}
-		
-		return result.Map(static result => result switch {
-			ConfigureInstanceResult.Success => CreateOrUpdateInstanceResult.Success,
-			_                               => CreateOrUpdateInstanceResult.UnknownError
-		});
 	}
 	
 	private void UpdateInstanceStatus(UpdateInstanceStatusCommand command) {
 		TellInstance(command.InstanceGuid, new InstanceActor.SetStatusCommand(command.Status));
 	}
 
-	private Task<InstanceActionResult<LaunchInstanceResult>> LaunchInstance(LaunchInstanceCommand command) {
+	private Task<Result<LaunchInstanceResult, InstanceActionFailure>> LaunchInstance(LaunchInstanceCommand command) {
 		return RequestInstance<InstanceActor.LaunchInstanceCommand, LaunchInstanceResult>(command.InstanceGuid, new InstanceActor.LaunchInstanceCommand(command.AuditLogUserGuid));
 	}
 
-	private Task<InstanceActionResult<StopInstanceResult>> StopInstance(StopInstanceCommand command) {
+	private Task<Result<StopInstanceResult, InstanceActionFailure>> StopInstance(StopInstanceCommand command) {
 		return RequestInstance<InstanceActor.StopInstanceCommand, StopInstanceResult>(command.InstanceGuid, new InstanceActor.StopInstanceCommand(command.AuditLogUserGuid, command.StopStrategy));
 	}
 
-	private Task<InstanceActionResult<SendCommandToInstanceResult>> SendMinecraftCommand(SendCommandToInstanceCommand command) {
+	private Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> SendMinecraftCommand(SendCommandToInstanceCommand command) {
 		return RequestInstance<InstanceActor.SendCommandToInstanceCommand, SendCommandToInstanceResult>(command.InstanceGuid, new InstanceActor.SendCommandToInstanceCommand(command.AuditLogUserGuid, command.Command));
 	}
 
diff --git a/Controller/Phantom.Controller.Services/Agents/AgentManager.cs b/Controller/Phantom.Controller.Services/Agents/AgentManager.cs
index abb37b8..874f6bf 100644
--- a/Controller/Phantom.Controller.Services/Agents/AgentManager.cs
+++ b/Controller/Phantom.Controller.Services/Agents/AgentManager.cs
@@ -83,12 +83,7 @@ sealed class AgentManager {
 		}
 	}
 
-	public async Task<InstanceActionResult<TReply>> DoInstanceAction<TCommand, TReply>(Guid agentGuid, TCommand command) where TCommand : class, AgentActor.ICommand, ICanReply<InstanceActionResult<TReply>> {
-		if (agentsByGuid.TryGetValue(agentGuid, out var agent)) {
-			return await agent.Request(command, cancellationToken);
-		}
-		else {
-			return InstanceActionResult.General<TReply>(InstanceActionGeneralResult.AgentDoesNotExist);
-		}
+	public async Task<Result<TReply, InstanceActionFailure>> DoInstanceAction<TCommand, TReply>(Guid agentGuid, TCommand command) where TCommand : class, AgentActor.ICommand, ICanReply<Result<TReply, InstanceActionFailure>> {
+		return agentsByGuid.TryGetValue(agentGuid, out var agent) ? await agent.Request(command, cancellationToken) : InstanceActionFailure.AgentDoesNotExist;
 	}
 }
diff --git a/Controller/Phantom.Controller.Services/Instances/InstanceActor.cs b/Controller/Phantom.Controller.Services/Instances/InstanceActor.cs
index 1f5f22a..267ebce 100644
--- a/Controller/Phantom.Controller.Services/Instances/InstanceActor.cs
+++ b/Controller/Phantom.Controller.Services/Instances/InstanceActor.cs
@@ -1,4 +1,5 @@
-using Phantom.Common.Data.Instance;
+using Phantom.Common.Data;
+using Phantom.Common.Data.Instance;
 using Phantom.Common.Data.Minecraft;
 using Phantom.Common.Data.Replies;
 using Phantom.Common.Data.Web.Instance;
@@ -39,10 +40,10 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
 		this.databaseStorageActor = Context.ActorOf(InstanceDatabaseStorageActor.Factory(new InstanceDatabaseStorageActor.Init(instanceGuid, init.DbProvider, init.CancellationToken)), "DatabaseStorage");
 
 		Receive<SetStatusCommand>(SetStatus);
-		ReceiveAsyncAndReply<ConfigureInstanceCommand, InstanceActionResult<ConfigureInstanceResult>>(ConfigureInstance);
-		ReceiveAsyncAndReply<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance);
-		ReceiveAsyncAndReply<StopInstanceCommand, InstanceActionResult<StopInstanceResult>>(StopInstance);
-		ReceiveAsyncAndReply<SendCommandToInstanceCommand, InstanceActionResult<SendCommandToInstanceResult>>(SendMinecraftCommand);
+		ReceiveAsyncAndReply<ConfigureInstanceCommand, Result<ConfigureInstanceResult, InstanceActionFailure>>(ConfigureInstance);
+		ReceiveAsyncAndReply<LaunchInstanceCommand, Result<LaunchInstanceResult, InstanceActionFailure>>(LaunchInstance);
+		ReceiveAsyncAndReply<StopInstanceCommand, Result<StopInstanceResult, InstanceActionFailure>>(StopInstance);
+		ReceiveAsyncAndReply<SendCommandToInstanceCommand, Result<SendCommandToInstanceResult, InstanceActionFailure>>(SendMinecraftCommand);
 	}
 
 	private void NotifyInstanceUpdated() {
@@ -56,29 +57,29 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
 		}
 	}
 
-	private async Task<InstanceActionResult<TReply>> SendInstanceActionMessage<TMessage, TReply>(TMessage message) where TMessage : IMessageToAgent, ICanReply<InstanceActionResult<TReply>> {
-		var reply = await agentConnection.Send<TMessage, InstanceActionResult<TReply>>(message, TimeSpan.FromSeconds(10), cancellationToken);
-		return reply.DidNotReplyIfNull();
+	private async Task<Result<TReply, InstanceActionFailure>> SendInstanceActionMessage<TMessage, TReply>(TMessage message) where TMessage : IMessageToAgent, ICanReply<Result<TReply, InstanceActionFailure>> {
+		var reply = await agentConnection.Send<TMessage, Result<TReply, InstanceActionFailure>>(message, TimeSpan.FromSeconds(10), cancellationToken);
+		return reply ?? InstanceActionFailure.AgentIsNotResponding;
 	}
 
 	public interface ICommand {}
 
 	public sealed record SetStatusCommand(IInstanceStatus Status) : ICommand;
 
-	public sealed record ConfigureInstanceCommand(Guid AuditLogUserGuid, Guid InstanceGuid, InstanceConfiguration Configuration, InstanceLaunchProperties LaunchProperties, bool IsCreatingInstance) : ICommand, ICanReply<InstanceActionResult<ConfigureInstanceResult>>;
+	public sealed record ConfigureInstanceCommand(Guid AuditLogUserGuid, Guid InstanceGuid, InstanceConfiguration Configuration, InstanceLaunchProperties LaunchProperties, bool IsCreatingInstance) : ICommand, ICanReply<Result<ConfigureInstanceResult, InstanceActionFailure>>;
 
-	public sealed record LaunchInstanceCommand(Guid AuditLogUserGuid) : ICommand, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
+	public sealed record LaunchInstanceCommand(Guid AuditLogUserGuid) : ICommand, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
 	
-	public sealed record StopInstanceCommand(Guid AuditLogUserGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<InstanceActionResult<StopInstanceResult>>;
+	public sealed record StopInstanceCommand(Guid AuditLogUserGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<Result<StopInstanceResult, InstanceActionFailure>>;
 	
-	public sealed record SendCommandToInstanceCommand(Guid AuditLogUserGuid, string Command) : ICommand, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
+	public sealed record SendCommandToInstanceCommand(Guid AuditLogUserGuid, string Command) : ICommand, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
 
 	private void SetStatus(SetStatusCommand command) {
 		status = command.Status;
 		NotifyInstanceUpdated();
 	}
 
-	private async Task<InstanceActionResult<ConfigureInstanceResult>> ConfigureInstance(ConfigureInstanceCommand command) {
+	private async Task<Result<ConfigureInstanceResult, InstanceActionFailure>> ConfigureInstance(ConfigureInstanceCommand command) {
 		var message = new ConfigureInstanceMessage(command.InstanceGuid, command.Configuration, command.LaunchProperties);
 		var result = await SendInstanceActionMessage<ConfigureInstanceMessage, ConfigureInstanceResult>(message);
 		
@@ -98,7 +99,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
 		return result;
 	}
 
-	private async Task<InstanceActionResult<LaunchInstanceResult>> LaunchInstance(LaunchInstanceCommand command) {
+	private async Task<Result<LaunchInstanceResult, InstanceActionFailure>> LaunchInstance(LaunchInstanceCommand command) {
 		var message = new LaunchInstanceMessage(instanceGuid);
 		var result = await SendInstanceActionMessage<LaunchInstanceMessage, LaunchInstanceResult>(message);
 		
@@ -110,7 +111,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
 		return result;
 	}
 
-	private async Task<InstanceActionResult<StopInstanceResult>> StopInstance(StopInstanceCommand command) {
+	private async Task<Result<StopInstanceResult, InstanceActionFailure>> StopInstance(StopInstanceCommand command) {
 		var message = new StopInstanceMessage(instanceGuid, command.StopStrategy);
 		var result = await SendInstanceActionMessage<StopInstanceMessage, StopInstanceResult>(message);
 		
@@ -122,7 +123,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
 		return result;
 	}
 
-	private async Task<InstanceActionResult<SendCommandToInstanceResult>> SendMinecraftCommand(SendCommandToInstanceCommand command) {
+	private async Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> SendMinecraftCommand(SendCommandToInstanceCommand command) {
 		var message = new SendCommandToInstanceMessage(instanceGuid, command.Command);
 		var result = await SendInstanceActionMessage<SendCommandToInstanceMessage, SendCommandToInstanceResult>(message);
 		
diff --git a/Controller/Phantom.Controller.Services/Rpc/WebMessageHandlerActor.cs b/Controller/Phantom.Controller.Services/Rpc/WebMessageHandlerActor.cs
index 7f64630..0ce7093 100644
--- a/Controller/Phantom.Controller.Services/Rpc/WebMessageHandlerActor.cs
+++ b/Controller/Phantom.Controller.Services/Rpc/WebMessageHandlerActor.cs
@@ -80,10 +80,10 @@ sealed class WebMessageHandlerActor : ReceiveActor<IMessageToController> {
 		ReceiveAndReplyLater<GetUserRolesMessage, ImmutableDictionary<Guid, ImmutableArray<Guid>>>(HandleGetUserRoles);
 		ReceiveAndReplyLater<ChangeUserRolesMessage, ChangeUserRolesResult>(HandleChangeUserRoles);
 		ReceiveAndReplyLater<DeleteUserMessage, DeleteUserResult>(HandleDeleteUser);
-		ReceiveAndReplyLater<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(HandleCreateOrUpdateInstance);
-		ReceiveAndReplyLater<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(HandleLaunchInstance);
-		ReceiveAndReplyLater<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(HandleStopInstance);
-		ReceiveAndReplyLater<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(HandleSendCommandToInstance);
+		ReceiveAndReplyLater<CreateOrUpdateInstanceMessage, Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(HandleCreateOrUpdateInstance);
+		ReceiveAndReplyLater<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(HandleLaunchInstance);
+		ReceiveAndReplyLater<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(HandleStopInstance);
+		ReceiveAndReplyLater<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(HandleSendCommandToInstance);
 		ReceiveAndReplyLater<GetMinecraftVersionsMessage, ImmutableArray<MinecraftVersion>>(HandleGetMinecraftVersions); 
 		ReceiveAndReply<GetAgentJavaRuntimesMessage, ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>>(HandleGetAgentJavaRuntimes);
 		ReceiveAndReplyLater<GetAuditLogMessage, ImmutableArray<AuditLogItem>>(HandleGetAuditLog);
@@ -139,19 +139,19 @@ sealed class WebMessageHandlerActor : ReceiveActor<IMessageToController> {
 		return userManager.DeleteByGuid(message.LoggedInUserGuid, message.SubjectUserGuid);
 	}
 
-	private Task<InstanceActionResult<CreateOrUpdateInstanceResult>> HandleCreateOrUpdateInstance(CreateOrUpdateInstanceMessage message) {
+	private Task<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>> HandleCreateOrUpdateInstance(CreateOrUpdateInstanceMessage message) {
 		return agentManager.DoInstanceAction<AgentActor.CreateOrUpdateInstanceCommand, CreateOrUpdateInstanceResult>(message.Configuration.AgentGuid, new AgentActor.CreateOrUpdateInstanceCommand(message.LoggedInUserGuid, message.InstanceGuid, message.Configuration));
 	}
 
-	private Task<InstanceActionResult<LaunchInstanceResult>> HandleLaunchInstance(LaunchInstanceMessage message) {
+	private Task<Result<LaunchInstanceResult, InstanceActionFailure>> HandleLaunchInstance(LaunchInstanceMessage message) {
 		return agentManager.DoInstanceAction<AgentActor.LaunchInstanceCommand, LaunchInstanceResult>(message.AgentGuid, new AgentActor.LaunchInstanceCommand(message.InstanceGuid, message.LoggedInUserGuid));
 	}
 
-	private Task<InstanceActionResult<StopInstanceResult>> HandleStopInstance(StopInstanceMessage message) {
+	private Task<Result<StopInstanceResult, InstanceActionFailure>> HandleStopInstance(StopInstanceMessage message) {
 		return agentManager.DoInstanceAction<AgentActor.StopInstanceCommand, StopInstanceResult>(message.AgentGuid, new AgentActor.StopInstanceCommand(message.InstanceGuid, message.LoggedInUserGuid, message.StopStrategy));
 	}
 
-	private Task<InstanceActionResult<SendCommandToInstanceResult>> HandleSendCommandToInstance(SendCommandToInstanceMessage message) {
+	private Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> HandleSendCommandToInstance(SendCommandToInstanceMessage message) {
 		return agentManager.DoInstanceAction<AgentActor.SendCommandToInstanceCommand, SendCommandToInstanceResult>(message.AgentGuid, new AgentActor.SendCommandToInstanceCommand(message.InstanceGuid, message.LoggedInUserGuid, message.Command));
 	}
 
diff --git a/Web/Phantom.Web.Services/Instances/InstanceManager.cs b/Web/Phantom.Web.Services/Instances/InstanceManager.cs
index 578a4ff..2794299 100644
--- a/Web/Phantom.Web.Services/Instances/InstanceManager.cs
+++ b/Web/Phantom.Web.Services/Instances/InstanceManager.cs
@@ -1,4 +1,5 @@
 using System.Collections.Immutable;
+using Phantom.Common.Data;
 using Phantom.Common.Data.Instance;
 using Phantom.Common.Data.Minecraft;
 using Phantom.Common.Data.Replies;
@@ -34,23 +35,23 @@ public sealed class InstanceManager {
 		return instances.Value.GetValueOrDefault(instanceGuid);
 	}
 
-	public Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance(Guid loggedInUserGuid, Guid instanceGuid, InstanceConfiguration configuration, CancellationToken cancellationToken) {
+	public Task<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>> CreateOrUpdateInstance(Guid loggedInUserGuid, Guid instanceGuid, InstanceConfiguration configuration, CancellationToken cancellationToken) {
 		var message = new CreateOrUpdateInstanceMessage(loggedInUserGuid, instanceGuid, configuration);
-		return controllerConnection.Send<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(message, cancellationToken);
+		return controllerConnection.Send<CreateOrUpdateInstanceMessage, Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(message, cancellationToken);
 	}
 
-	public Task<InstanceActionResult<LaunchInstanceResult>> LaunchInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, CancellationToken cancellationToken) {
+	public Task<Result<LaunchInstanceResult, InstanceActionFailure>> LaunchInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, CancellationToken cancellationToken) {
 		var message = new LaunchInstanceMessage(loggedInUserGuid, agentGuid, instanceGuid);
-		return controllerConnection.Send<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(message, cancellationToken);
+		return controllerConnection.Send<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(message, cancellationToken);
 	}
 
-	public Task<InstanceActionResult<StopInstanceResult>> StopInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, MinecraftStopStrategy stopStrategy, CancellationToken cancellationToken) {
+	public Task<Result<StopInstanceResult, InstanceActionFailure>> StopInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, MinecraftStopStrategy stopStrategy, CancellationToken cancellationToken) {
 		var message = new StopInstanceMessage(loggedInUserGuid, agentGuid, instanceGuid, stopStrategy);
-		return controllerConnection.Send<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(message, cancellationToken);
+		return controllerConnection.Send<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(message, cancellationToken);
 	}
 
-	public Task<InstanceActionResult<SendCommandToInstanceResult>> SendCommandToInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, string command, CancellationToken cancellationToken) {
+	public Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> SendCommandToInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, string command, CancellationToken cancellationToken) {
 		var message = new SendCommandToInstanceMessage(loggedInUserGuid, agentGuid, instanceGuid, command);
-		return controllerConnection.Send<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(message, cancellationToken);
+		return controllerConnection.Send<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(message, cancellationToken);
 	}
 }
diff --git a/Web/Phantom.Web/Pages/InstanceDetail.razor b/Web/Phantom.Web/Pages/InstanceDetail.razor
index c6ab320..b232938 100644
--- a/Web/Phantom.Web/Pages/InstanceDetail.razor
+++ b/Web/Phantom.Web/Pages/InstanceDetail.razor
@@ -86,7 +86,7 @@ else {
 
       var result = await InstanceManager.LaunchInstance(loggedInUserGuid.Value, Instance.Configuration.AgentGuid, InstanceGuid, CancellationToken);
       if (!result.Is(LaunchInstanceResult.LaunchInitiated)) {
-        lastError = result.ToSentence(Messages.ToSentence);
+        lastError = result.Map(Messages.ToSentence, InstanceActionFailureExtensions.ToSentence);
       }
     } finally {
       isLaunchingInstance = false;
diff --git a/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor b/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor
index 6ac26b6..8913d78 100644
--- a/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor
+++ b/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor
@@ -3,6 +3,7 @@
 @using System.ComponentModel.DataAnnotations
 @using System.Diagnostics.CodeAnalysis
 @using Phantom.Common.Data.Minecraft
+@using Phantom.Common.Data.Replies
 @using Phantom.Common.Data.Web.Agent
 @using Phantom.Common.Data.Web.Instance
 @using Phantom.Common.Data.Web.Minecraft
@@ -347,7 +348,7 @@
       await Navigation.NavigateTo("instances/" + instanceGuid);
     }
     else {
-      form.SubmitModel.StopSubmitting(result.ToSentence(CreateOrUpdateInstanceResultExtensions.ToSentence));
+      form.SubmitModel.StopSubmitting(result.Map(CreateOrUpdateInstanceResultExtensions.ToSentence, InstanceActionFailureExtensions.ToSentence));
     }
   }
 
diff --git a/Web/Phantom.Web/Shared/InstanceCommandInput.razor b/Web/Phantom.Web/Shared/InstanceCommandInput.razor
index c6bd0ab..8fd6a4e 100644
--- a/Web/Phantom.Web/Shared/InstanceCommandInput.razor
+++ b/Web/Phantom.Web/Shared/InstanceCommandInput.razor
@@ -48,7 +48,7 @@
       form.SubmitModel.StopSubmitting();
     }
     else {
-      form.SubmitModel.StopSubmitting(result.ToSentence(Messages.ToSentence));
+      form.SubmitModel.StopSubmitting(result.Map(Messages.ToSentence, InstanceActionFailureExtensions.ToSentence));
     }
 
     await commandInputElement.FocusAsync(preventScroll: true);
diff --git a/Web/Phantom.Web/Shared/InstanceStopDialog.razor b/Web/Phantom.Web/Shared/InstanceStopDialog.razor
index 79df39f..f2ff23c 100644
--- a/Web/Phantom.Web/Shared/InstanceStopDialog.razor
+++ b/Web/Phantom.Web/Shared/InstanceStopDialog.razor
@@ -65,7 +65,7 @@
       form.SubmitModel.StopSubmitting();
     }
     else {
-      form.SubmitModel.StopSubmitting(result.ToSentence(Messages.ToSentence));
+      form.SubmitModel.StopSubmitting(result.Map(Messages.ToSentence, InstanceActionFailureExtensions.ToSentence));
     }
   }