From d0634fc141fe166e0690262f748e1b611a3aaf9a Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 12:58:29 -0700
Subject: [PATCH 1/6] validator: update rbx_asset

---
 Cargo.lock               | 4 ++--
 validation/Cargo.toml    | 2 +-
 validation/src/create.rs | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 2f71fec..28333f6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1297,9 +1297,9 @@ dependencies = [
 
 [[package]]
 name = "rbx_asset"
-version = "0.2.5"
+version = "0.3.3"
 source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
-checksum = "dcf243f46bd41b3880a27278177a3f9996f95ab231d9a04345ad9dd381c3a54a"
+checksum = "91722b37549ded270f39556194ca03d03e08bd70674d239ec845765ed9e42b7d"
 dependencies = [
  "chrono",
  "flate2",
diff --git a/validation/Cargo.toml b/validation/Cargo.toml
index 28ce533..ee5dffa 100644
--- a/validation/Cargo.toml
+++ b/validation/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
 submissions-api = { path = "api", features = ["internal"], default-features = false, registry = "strafesnet" }
 async-nats = "0.40.0"
 futures = "0.3.31"
-rbx_asset = { version = "0.2.5", registry = "strafesnet" }
+rbx_asset = { version = "0.3.3", registry = "strafesnet" }
 rbx_binary = { version = "0.7.4", registry = "strafesnet"}
 rbx_dom_weak = { version = "2.9.0", registry = "strafesnet"}
 rbx_reflection_database = { version = "0.2.12", registry = "strafesnet"}
diff --git a/validation/src/create.rs b/validation/src/create.rs
index 1513904..76c4a05 100644
--- a/validation/src/create.rs
+++ b/validation/src/create.rs
@@ -41,7 +41,7 @@ impl crate::message_handler::MessageHandler{
 		// grab version info
 		let first_version=asset_versions_page.data.first().ok_or(Error::EmptyVersionsPage)?;
 
-		if first_version.creatorType!="User"{
+		if first_version.creatorType!=rbx_asset::cookie::CreatorType::User{
 			return Err(Error::WrongCreatorType);
 		}
 
-- 
2.47.1


From a3d644f57207eb0623dc249753072d762fe9db87 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 13:10:48 -0700
Subject: [PATCH 2/6] validator: use different endpoints to fill in the
 submission details

---
 validation/src/create.rs | 47 +++++++++++++++++++++++-----------------
 1 file changed, 27 insertions(+), 20 deletions(-)

diff --git a/validation/src/create.rs b/validation/src/create.rs
index 76c4a05..747a824 100644
--- a/validation/src/create.rs
+++ b/validation/src/create.rs
@@ -5,8 +5,11 @@ use crate::rbx_util::{get_mapinfo,read_dom,MapInfo,ReadDomError,GetMapInfoError,
 pub enum Error{
 	ModelVersionsPage(rbx_asset::cookie::PageError),
 	EmptyVersionsPage,
-	WrongCreatorType,
+	CreatorTypeMustBeUser(rbx_asset::cookie::CreatorType),
+	ModelDetails(rbx_asset::cookie::GetError),
+	ModelInfoDownload(rbx_asset::cookie::GetAssetV2Error),
 	ModelFileDownload(rbx_asset::cookie::GetError),
+	NoLocations,
 	ModelFileDecode(ReadDomError),
 	GetMapInfo(GetMapInfoError),
 	ParseGameID(ParseGameIDError),
@@ -32,28 +35,32 @@ pub struct CreateResult{
 }
 impl crate::message_handler::MessageHandler{
 	pub async fn create_inner(&self,create_info:CreateRequest)->Result<CreateResult,Error>{
-		// discover the latest asset version
-		let asset_versions_page=self.cookie_context.get_asset_versions_page(rbx_asset::cookie::AssetVersionsPageRequest{
-			asset_id:create_info.ModelID,
-			cursor:None
-		}).await.map_err(Error::ModelVersionsPage)?;
+		// discover asset creator
+		let creator_fut=async{
+			self.cookie_context.get_asset_details(
+				rbx_asset::cookie::GetAssetDetailsRequest{asset_id:create_info.ModelID}
+			).await.map_err(Error::ModelDetails)
+		};
 
-		// grab version info
-		let first_version=asset_versions_page.data.first().ok_or(Error::EmptyVersionsPage)?;
+		// download the map model
+		let asset_fut=async{
+			let asset_info=self.cookie_context.get_asset_v2(rbx_asset::cookie::GetAssetRequest{
+				asset_id:create_info.ModelID,
+				version:None,
+			}).await.map_err(Error::ModelInfoDownload)?;
 
-		if first_version.creatorType!=rbx_asset::cookie::CreatorType::User{
-			return Err(Error::WrongCreatorType);
+			let location=asset_info.info.locations.first().ok_or(Error::NoLocations)?;
+			let data=self.cookie_context.get_asset_v2_download(location).await.map_err(Error::ModelFileDownload)?;
+
+			Ok((asset_info.version,data))
+		};
+
+		let (details,(asset_version,model_data))=tokio::try_join!(creator_fut,asset_fut)?;
+
+		if details.Creator.CreatorType!=rbx_asset::cookie::CreatorType::User{
+			return Err(Error::CreatorTypeMustBeUser(details.Creator.CreatorType));
 		}
 
-		let asset_creator_id=first_version.creatorTargetId;
-		let asset_version=first_version.assetVersionNumber;
-
-		// download the map model version
-		let model_data=self.cookie_context.get_asset(rbx_asset::cookie::GetAssetRequest{
-			asset_id:create_info.ModelID,
-			version:Some(asset_version),
-		}).await.map_err(Error::ModelFileDownload)?;
-
 		// decode dom (slow!)
 		let dom=read_dom(&mut std::io::Cursor::new(model_data)).map_err(Error::ModelFileDecode)?;
 
@@ -67,7 +74,7 @@ impl crate::message_handler::MessageHandler{
 		let game_id=game_id.map_err(Error::ParseGameID)?;
 
 		Ok(CreateResult{
-			AssetOwner:asset_creator_id as i64,
+			AssetOwner:details.Creator.Id as i64,
 			DisplayName:display_name.unwrap_or_default().to_owned(),
 			Creator:creator.unwrap_or_default().to_owned(),
 			GameID:game_id as i32,
-- 
2.47.1


From 027a55661bc835032a9dc45797e003a9b394d123 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 13:17:43 -0700
Subject: [PATCH 3/6] openapi: be consistent

---
 openapi-internal.yaml              | 2 +-
 pkg/service_internal/operations.go | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/openapi-internal.yaml b/openapi-internal.yaml
index f92b03b..9040e92 100644
--- a/openapi-internal.yaml
+++ b/openapi-internal.yaml
@@ -121,7 +121,7 @@ paths:
             application/json:
               schema:
                 $ref: "#/components/schemas/Error"
-  /operations/{OperationID}/failed:
+  /operations/{OperationID}/status/operation-failed:
     post:
       summary: (Internal endpoint) Fail an operation and write a StatusMessage
       operationId: actionOperationFailed
diff --git a/pkg/service_internal/operations.go b/pkg/service_internal/operations.go
index 2deeffd..87ccccc 100644
--- a/pkg/service_internal/operations.go
+++ b/pkg/service_internal/operations.go
@@ -12,7 +12,7 @@ import (
 //
 // Fail the specified OperationID with a StatusMessage.
 //
-// POST /operations/{OperationID}/failed
+// POST /operations/{OperationID}/status/operation-failed
 func (svc *Service) ActionOperationFailed(ctx context.Context, params internal.ActionOperationFailedParams) (error) {
 	pmap := datastore.Optional()
 	pmap.Add("status_id", model.OperationStatusFailed)
-- 
2.47.1


From fe2c20bd72e5064364e412489fa07c871719ea60 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 13:17:59 -0700
Subject: [PATCH 4/6] openapi: generate

---
 pkg/internal/oas_client_gen.go        |  8 ++++----
 pkg/internal/oas_handlers_gen.go      |  4 ++--
 pkg/internal/oas_router_gen.go        | 10 +++++-----
 pkg/internal/oas_server_gen.go        |  2 +-
 pkg/internal/oas_unimplemented_gen.go |  2 +-
 5 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/pkg/internal/oas_client_gen.go b/pkg/internal/oas_client_gen.go
index d57735f..0248a3f 100644
--- a/pkg/internal/oas_client_gen.go
+++ b/pkg/internal/oas_client_gen.go
@@ -50,7 +50,7 @@ type Invoker interface {
 	//
 	// (Internal endpoint) Fail an operation and write a StatusMessage.
 	//
-	// POST /operations/{OperationID}/failed
+	// POST /operations/{OperationID}/status/operation-failed
 	ActionOperationFailed(ctx context.Context, params ActionOperationFailedParams) error
 	// ActionSubmissionAccepted invokes actionSubmissionAccepted operation.
 	//
@@ -468,7 +468,7 @@ func (c *Client) sendActionMapfixValidated(ctx context.Context, params ActionMap
 //
 // (Internal endpoint) Fail an operation and write a StatusMessage.
 //
-// POST /operations/{OperationID}/failed
+// POST /operations/{OperationID}/status/operation-failed
 func (c *Client) ActionOperationFailed(ctx context.Context, params ActionOperationFailedParams) error {
 	_, err := c.sendActionOperationFailed(ctx, params)
 	return err
@@ -478,7 +478,7 @@ func (c *Client) sendActionOperationFailed(ctx context.Context, params ActionOpe
 	otelAttrs := []attribute.KeyValue{
 		otelogen.OperationID("actionOperationFailed"),
 		semconv.HTTPRequestMethodKey.String("POST"),
-		semconv.HTTPRouteKey.String("/operations/{OperationID}/failed"),
+		semconv.HTTPRouteKey.String("/operations/{OperationID}/status/operation-failed"),
 	}
 
 	// Run stopwatch.
@@ -530,7 +530,7 @@ func (c *Client) sendActionOperationFailed(ctx context.Context, params ActionOpe
 		}
 		pathParts[1] = encoded
 	}
-	pathParts[2] = "/failed"
+	pathParts[2] = "/status/operation-failed"
 	uri.AddPathParts(u, pathParts[:]...)
 
 	stage = "EncodeQueryParams"
diff --git a/pkg/internal/oas_handlers_gen.go b/pkg/internal/oas_handlers_gen.go
index 96b8c4b..b382980 100644
--- a/pkg/internal/oas_handlers_gen.go
+++ b/pkg/internal/oas_handlers_gen.go
@@ -485,14 +485,14 @@ func (s *Server) handleActionMapfixValidatedRequest(args [1]string, argsEscaped
 //
 // (Internal endpoint) Fail an operation and write a StatusMessage.
 //
-// POST /operations/{OperationID}/failed
+// POST /operations/{OperationID}/status/operation-failed
 func (s *Server) handleActionOperationFailedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
 	statusWriter := &codeRecorder{ResponseWriter: w}
 	w = statusWriter
 	otelAttrs := []attribute.KeyValue{
 		otelogen.OperationID("actionOperationFailed"),
 		semconv.HTTPRequestMethodKey.String("POST"),
-		semconv.HTTPRouteKey.String("/operations/{OperationID}/failed"),
+		semconv.HTTPRouteKey.String("/operations/{OperationID}/status/operation-failed"),
 	}
 
 	// Start a span for this request.
diff --git a/pkg/internal/oas_router_gen.go b/pkg/internal/oas_router_gen.go
index 0531e26..ecc609b 100644
--- a/pkg/internal/oas_router_gen.go
+++ b/pkg/internal/oas_router_gen.go
@@ -242,9 +242,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 					break
 				}
 				switch elem[0] {
-				case '/': // Prefix: "/failed"
+				case '/': // Prefix: "/status/operation-failed"
 
-					if l := len("/failed"); len(elem) >= l && elem[0:l] == "/failed" {
+					if l := len("/status/operation-failed"); len(elem) >= l && elem[0:l] == "/status/operation-failed" {
 						elem = elem[l:]
 					} else {
 						break
@@ -817,9 +817,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 					break
 				}
 				switch elem[0] {
-				case '/': // Prefix: "/failed"
+				case '/': // Prefix: "/status/operation-failed"
 
-					if l := len("/failed"); len(elem) >= l && elem[0:l] == "/failed" {
+					if l := len("/status/operation-failed"); len(elem) >= l && elem[0:l] == "/status/operation-failed" {
 						elem = elem[l:]
 					} else {
 						break
@@ -832,7 +832,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 							r.name = ActionOperationFailedOperation
 							r.summary = "(Internal endpoint) Fail an operation and write a StatusMessage"
 							r.operationID = "actionOperationFailed"
-							r.pathPattern = "/operations/{OperationID}/failed"
+							r.pathPattern = "/operations/{OperationID}/status/operation-failed"
 							r.args = args
 							r.count = 1
 							return r, true
diff --git a/pkg/internal/oas_server_gen.go b/pkg/internal/oas_server_gen.go
index b19609a..4fd886c 100644
--- a/pkg/internal/oas_server_gen.go
+++ b/pkg/internal/oas_server_gen.go
@@ -30,7 +30,7 @@ type Handler interface {
 	//
 	// (Internal endpoint) Fail an operation and write a StatusMessage.
 	//
-	// POST /operations/{OperationID}/failed
+	// POST /operations/{OperationID}/status/operation-failed
 	ActionOperationFailed(ctx context.Context, params ActionOperationFailedParams) error
 	// ActionSubmissionAccepted implements actionSubmissionAccepted operation.
 	//
diff --git a/pkg/internal/oas_unimplemented_gen.go b/pkg/internal/oas_unimplemented_gen.go
index 1adcfdf..e231989 100644
--- a/pkg/internal/oas_unimplemented_gen.go
+++ b/pkg/internal/oas_unimplemented_gen.go
@@ -44,7 +44,7 @@ func (UnimplementedHandler) ActionMapfixValidated(ctx context.Context, params Ac
 //
 // (Internal endpoint) Fail an operation and write a StatusMessage.
 //
-// POST /operations/{OperationID}/failed
+// POST /operations/{OperationID}/status/operation-failed
 func (UnimplementedHandler) ActionOperationFailed(ctx context.Context, params ActionOperationFailedParams) error {
 	return ht.ErrNotImplemented
 }
-- 
2.47.1


From 56681f88622b7c57314883b3413614b653f544b5 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 13:31:32 -0700
Subject: [PATCH 5/6] submissions: mark operation as completed

---
 pkg/service_internal/mapfixes.go    | 11 +++++++++++
 pkg/service_internal/submissions.go | 11 +++++++++++
 2 files changed, 22 insertions(+)

diff --git a/pkg/service_internal/mapfixes.go b/pkg/service_internal/mapfixes.go
index b792f72..e0f7375 100644
--- a/pkg/service_internal/mapfixes.go
+++ b/pkg/service_internal/mapfixes.go
@@ -3,6 +3,7 @@ package service_internal
 import (
 	"context"
 	"errors"
+	"fmt"
 
 	"git.itzana.me/strafesnet/maps-service/pkg/datastore"
 	internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
@@ -125,6 +126,16 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *internal.MapfixCr
 	if err != nil {
 		return nil, err
 	}
+
+	// mark the operation as completed and provide the path
+	pmap := datastore.Optional()
+	pmap.Add("status_id", model.OperationStatusCompleted)
+	pmap.Add("path", fmt.Sprintf("/mapfixes/%d", mapfix.ID))
+	err = svc.DB.Operations().Update(ctx, request.OperationID, pmap)
+	if err != nil {
+		return nil, err
+	}
+
 	return &internal.MapfixID{
 		MapfixID: mapfix.ID,
 	}, nil
diff --git a/pkg/service_internal/submissions.go b/pkg/service_internal/submissions.go
index 3322230..b445c64 100644
--- a/pkg/service_internal/submissions.go
+++ b/pkg/service_internal/submissions.go
@@ -3,6 +3,7 @@ package service_internal
 import (
 	"context"
 	"errors"
+	"fmt"
 
 	"git.itzana.me/strafesnet/maps-service/pkg/datastore"
 	internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
@@ -124,6 +125,16 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *internal.Subm
 	if err != nil {
 		return nil, err
 	}
+
+	// mark the operation as completed and provide the path
+	pmap := datastore.Optional()
+	pmap.Add("status_id", model.OperationStatusCompleted)
+	pmap.Add("path", fmt.Sprintf("/submissions/%d", submission.ID))
+	err = svc.DB.Operations().Update(ctx, request.OperationID, pmap)
+	if err != nil {
+		return nil, err
+	}
+
 	return &internal.SubmissionID{
 		SubmissionID: submission.ID,
 	}, nil
-- 
2.47.1


From ca1676db0021a25e57b036365b0fde9aa0b92f08 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 13:43:43 -0700
Subject: [PATCH 6/6] validation: catch final error

---
 validation/src/create_mapfix.rs     | 53 ++++++++++++++++-------------
 validation/src/create_submission.rs | 49 +++++++++++++-------------
 validation/src/message_handler.rs   |  4 +--
 3 files changed, 57 insertions(+), 49 deletions(-)

diff --git a/validation/src/create_mapfix.rs b/validation/src/create_mapfix.rs
index 6dbe905..982fd91 100644
--- a/validation/src/create_mapfix.rs
+++ b/validation/src/create_mapfix.rs
@@ -4,8 +4,8 @@ use crate::create::CreateRequest;
 #[allow(dead_code)]
 #[derive(Debug)]
 pub enum Error{
+	Create(crate::create::Error),
 	ApiActionMapfixCreate(submissions_api::Error),
-	ApiActionOperationFailed(submissions_api::Error),
 }
 impl std::fmt::Display for Error{
 	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -15,31 +15,36 @@ impl std::fmt::Display for Error{
 impl std::error::Error for Error{}
 
 impl crate::message_handler::MessageHandler{
-	pub async fn create_mapfix(&self,create_info:CreateMapfixRequest)->Result<(),Error>{
-		let create_result=self.create_inner(CreateRequest{
+	async fn create_mapfix_inner(&self,create_info:CreateMapfixRequest)->Result<(),Error>{
+		// call deduplicated inner code
+		let create_request=self.create_inner(CreateRequest{
 			ModelID:create_info.ModelID,
-		}).await;
+		}).await.map_err(Error::Create)?;
 
-		match create_result{
-			Ok(create_request)=>{
-				// call create on api
-				self.api.create_mapfix(submissions_api::types::CreateMapfixRequest{
-					OperationID:create_info.OperationID,
-					AssetOwner:create_request.AssetOwner,
-					DisplayName:create_request.DisplayName.as_str(),
-					Creator:create_request.Creator.as_str(),
-					GameID:create_request.GameID,
-					AssetID:create_info.ModelID,
-					AssetVersion:create_request.AssetVersion,
-					TargetAssetID:create_info.TargetAssetID,
-				}).await.map_err(Error::ApiActionMapfixCreate)?;
-			},
-			Err(e)=>{
-				self.api.action_operation_failed(submissions_api::types::ActionOperationFailedRequest{
-					OperationID:create_info.OperationID,
-					StatusMessage:format!("{e}"),
-				}).await.map_err(Error::ApiActionOperationFailed)?;
-			},
+		// call create on api
+		self.api.create_mapfix(submissions_api::types::CreateMapfixRequest{
+			OperationID:create_info.OperationID,
+			AssetOwner:create_request.AssetOwner,
+			DisplayName:create_request.DisplayName.as_str(),
+			Creator:create_request.Creator.as_str(),
+			GameID:create_request.GameID,
+			AssetID:create_info.ModelID,
+			AssetVersion:create_request.AssetVersion,
+			TargetAssetID:create_info.TargetAssetID,
+		}).await.map_err(Error::ApiActionMapfixCreate)?;
+
+		Ok(())
+	}
+	pub async fn create_mapfix(&self,create_info:CreateMapfixRequest)->Result<(),submissions_api::Error>{
+		let operation_id=create_info.OperationID;
+
+		let create_result=self.create_mapfix_inner(create_info).await;
+
+		if let Err(e)=create_result{
+			self.api.action_operation_failed(submissions_api::types::ActionOperationFailedRequest{
+				OperationID:operation_id,
+				StatusMessage:format!("{e}"),
+			}).await?;
 		}
 
 		Ok(())
diff --git a/validation/src/create_submission.rs b/validation/src/create_submission.rs
index 31f2a0e..4949366 100644
--- a/validation/src/create_submission.rs
+++ b/validation/src/create_submission.rs
@@ -4,8 +4,8 @@ use crate::create::CreateRequest;
 #[allow(dead_code)]
 #[derive(Debug)]
 pub enum Error{
+	Create(crate::create::Error),
 	ApiActionSubmissionCreate(submissions_api::Error),
-	ApiActionOperationFailed(submissions_api::Error),
 }
 impl std::fmt::Display for Error{
 	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -15,30 +15,33 @@ impl std::fmt::Display for Error{
 impl std::error::Error for Error{}
 
 impl crate::message_handler::MessageHandler{
-	pub async fn create_submission(&self,create_info:CreateSubmissionRequest)->Result<(),Error>{
-		let create_result=self.create_inner(CreateRequest{
+	async fn create_submission_inner(&self,create_info:CreateSubmissionRequest)->Result<(),Error>{
+		let create_request=self.create_inner(CreateRequest{
 			ModelID:create_info.ModelID,
-		}).await;
+		}).await.map_err(Error::Create)?;
+		// call create on api
+		self.api.create_submission(submissions_api::types::CreateSubmissionRequest{
+			OperationID:create_info.OperationID,
+			AssetOwner:create_request.AssetOwner,
+			DisplayName:create_request.DisplayName.as_str(),
+			Creator:create_request.Creator.as_str(),
+			GameID:create_request.GameID,
+			AssetID:create_info.ModelID,
+			AssetVersion:create_request.AssetVersion,
+		}).await.map_err(Error::ApiActionSubmissionCreate)?;
 
-		match create_result{
-			Ok(create_request)=>{
-				// call create on api
-				self.api.create_submission(submissions_api::types::CreateSubmissionRequest{
-					OperationID:create_info.OperationID,
-					AssetOwner:create_request.AssetOwner,
-					DisplayName:create_request.DisplayName.as_str(),
-					Creator:create_request.Creator.as_str(),
-					GameID:create_request.GameID,
-					AssetID:create_info.ModelID,
-					AssetVersion:create_request.AssetVersion,
-				}).await.map_err(Error::ApiActionSubmissionCreate)?;
-			},
-			Err(e)=>{
-				self.api.action_operation_failed(submissions_api::types::ActionOperationFailedRequest{
-					OperationID:create_info.OperationID,
-					StatusMessage:format!("{e}"),
-				}).await.map_err(Error::ApiActionOperationFailed)?;
-			},
+		Ok(())
+	}
+	pub async fn create_submission(&self,create_info:CreateSubmissionRequest)->Result<(),submissions_api::Error>{
+		let operation_id=create_info.OperationID;
+
+		let create_result=self.create_submission_inner(create_info).await;
+
+		if let Err(e)=create_result{
+			self.api.action_operation_failed(submissions_api::types::ActionOperationFailedRequest{
+				OperationID:operation_id,
+				StatusMessage:format!("{e}"),
+			}).await?;
 		}
 
 		Ok(())
diff --git a/validation/src/message_handler.rs b/validation/src/message_handler.rs
index bff0f10..fe79ee5 100644
--- a/validation/src/message_handler.rs
+++ b/validation/src/message_handler.rs
@@ -5,8 +5,8 @@ pub enum HandleMessageError{
 	DoubleAck(async_nats::Error),
 	Json(serde_json::Error),
 	UnknownSubject(String),
-	CreateMapfix(crate::create_mapfix::Error),
-	CreateSubmission(crate::create_submission::Error),
+	CreateMapfix(submissions_api::Error),
+	CreateSubmission(submissions_api::Error),
 	UploadMapfix(crate::upload_mapfix::Error),
 	UploadSubmission(crate::upload_submission::Error),
 	ValidateMapfix(crate::validate_mapfix::Error),
-- 
2.47.1