From d065480540cecfad2676a006fcedb0a555b212ca Mon Sep 17 00:00:00 2001 From: Martin Varga Date: Thu, 12 Mar 2026 13:23:33 +0100 Subject: [PATCH 1/3] Add debugging logs for file restore 404 issue --- server/mergin/sync/models.py | 15 +++++++++++++++ server/mergin/sync/public_api_controller.py | 7 ++++++- server/mergin/sync/storages/disk.py | 17 +++++++++++++---- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/server/mergin/sync/models.py b/server/mergin/sync/models.py index 6527213c..fc2eed79 100644 --- a/server/mergin/sync/models.py +++ b/server/mergin/sync/models.py @@ -725,10 +725,14 @@ def diffs_chain( ) # file never existed prior that version if not latest_change: + logging.warning(f"File {file_id} never existed prior version {version}") return None, [] # the last update to file was a delete if latest_change.change == PushChangeType.DELETE.value: + logging.warning( + f"File {file_id} latest change prior version {version} was delete" + ) return None, [] # the last update to file was a create / force update @@ -736,10 +740,14 @@ def diffs_chain( PushChangeType.CREATE.value, PushChangeType.UPDATE.value, ): + logging.warning( + f"File {file_id} latest change prior version {version} was {latest_change.change}" + ) return latest_change, [] basefile = cls.get_basefile(file_id, version) if not basefile: + logging.warning(f"File {file_id} has no basefile prior version {version}") return None, [] diffs = [] @@ -782,9 +790,16 @@ def diffs_chain( .order_by(FileDiff.version) .all() ) + logging.info( + f"File {file_id} checkpoint {item.version} of rank {item.rank} missing, " + f"replacing with {len(individual_diffs)} diffs" + ) diffs.extend(individual_diffs) else: # we asked for individual diff but there is no such diff as there was not change at that version + logging.warning( + f"File {file_id} checkpoint {item.version} of rank {item.rank} missing as there was no data change" + ) continue return basefile, diffs diff --git a/server/mergin/sync/public_api_controller.py b/server/mergin/sync/public_api_controller.py index 0cbd5e90..809e5719 100644 --- a/server/mergin/sync/public_api_controller.py +++ b/server/mergin/sync/public_api_controller.py @@ -337,12 +337,17 @@ def download_project_file( else: file_path = fh.location + abs_path = os.path.join(project.storage.project_dir, file_path) + if version and not diff: + logging.info(f"Restoring {namespace}/{project_name}/{file} at {version}") project.storage.restore_versioned_file( file, ProjectVersion.from_v_name(version) ) + if not os.path.exists(abs_path): + logging.error(f"Could not restore {namespace}/{project_name}/{file_path}") + abort(422) - abs_path = os.path.join(project.storage.project_dir, file_path) # check file exists (e.g. there might have been issue with restore) if not os.path.exists(abs_path): logging.error(f"Missing file {namespace}/{project_name}/{file_path}") diff --git a/server/mergin/sync/storages/disk.py b/server/mergin/sync/storages/disk.py index 02c0c8ed..b3a66ba0 100644 --- a/server/mergin/sync/storages/disk.py +++ b/server/mergin/sync/storages/disk.py @@ -375,6 +375,7 @@ def restore_versioned_file(self, file: str, version: int): ) if not is_versioned_file(file): + logging.warning(f"File {file} is not gpkg file") return # if project version is not found, return it @@ -382,15 +383,20 @@ def restore_versioned_file(self, file: str, version: int): project_id=self.project.id, name=version ).first() if not project_version: + logging.warning(f"Project version {version} for file {file} not found") return # check actual file from the version files file_found = next((i for i in project_version.files if i.path == file), None) - # check the location that we found on the file - if not file_found or os.path.exists( - os.path.join(self.project_dir, file_found.location) - ): + # check the file is found in files at particular version + if not file_found: + logging.warning(f"File {file} not found in version {version}") + return + + # check if file already exists + if os.path.exists(os.path.join(self.project_dir, file_found.location)): + logging.info(f"File {file} already exists at {version}") return file_id = ( @@ -401,6 +407,9 @@ def restore_versioned_file(self, file: str, version: int): base_meta, diffs = FileHistory.diffs_chain(file_id, version) if not (base_meta and diffs): + logging.warning( + f"File {file} at version {version} does not have basefile or there are no diffs" + ) return start = time.time() From 6f00af9ed2220111104375ae45a0e7ec4c2759d1 Mon Sep 17 00:00:00 2001 From: Martin Varga Date: Thu, 12 Mar 2026 13:50:09 +0100 Subject: [PATCH 2/3] Fix logging message --- server/mergin/sync/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/mergin/sync/models.py b/server/mergin/sync/models.py index fc2eed79..84dbe890 100644 --- a/server/mergin/sync/models.py +++ b/server/mergin/sync/models.py @@ -791,14 +791,14 @@ def diffs_chain( .all() ) logging.info( - f"File {file_id} checkpoint {item.version} of rank {item.rank} missing, " + f"File {file_id} checkpoint {item.end} of rank {item.rank} missing, " f"replacing with {len(individual_diffs)} diffs" ) diffs.extend(individual_diffs) else: # we asked for individual diff but there is no such diff as there was not change at that version logging.warning( - f"File {file_id} checkpoint {item.version} of rank {item.rank} missing as there was no data change" + f"File {file_id} checkpoint {item.end} of rank {item.rank} missing as there was no data change" ) continue From 01b82d779e8b3e091d50ef4e067746aba1b973d0 Mon Sep 17 00:00:00 2001 From: Martin Varga Date: Thu, 12 Mar 2026 14:05:32 +0100 Subject: [PATCH 3/3] Revert back status 404 code --- server/mergin/sync/public_api_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/mergin/sync/public_api_controller.py b/server/mergin/sync/public_api_controller.py index 809e5719..d36fd183 100644 --- a/server/mergin/sync/public_api_controller.py +++ b/server/mergin/sync/public_api_controller.py @@ -346,7 +346,7 @@ def download_project_file( ) if not os.path.exists(abs_path): logging.error(f"Could not restore {namespace}/{project_name}/{file_path}") - abort(422) + abort(404) # check file exists (e.g. there might have been issue with restore) if not os.path.exists(abs_path):