From d8aa12f012483f1400d5bb6007cfd715b4de2f0c Mon Sep 17 00:00:00 2001 From: Nico Hinderling Date: Mon, 22 Jun 2026 15:22:41 -0700 Subject: [PATCH 1/3] fix(api): Parse renamed project slug from top-level field --- src/api/mod.rs | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 24a3741844..ce98f49733 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1605,20 +1605,15 @@ impl ApiResponse { fn convert_rnf(self, res_err: ApiErrorKind) -> ApiResult { match self.status() { 301 | 302 if res_err == ApiErrorKind::ProjectNotFound => { - #[derive(Deserialize, Debug)] - struct ErrorDetail { - slug: String, - } - #[derive(Deserialize, Debug)] struct ErrorInfo { - detail: ErrorDetail, + slug: String, } match self.convert::() { Ok(info) => Err(ApiError::with_source( res_err, - ProjectRenamedError(info.detail.slug), + ProjectRenamedError(info.slug), )), Err(_) => Err(res_err.into()), } @@ -2143,3 +2138,35 @@ pub struct ObjectstoreUploadOptions { pub auth_token: Option, pub expiration_policy: String, } + +#[cfg(test)] +mod tests { + use std::error::Error as _; + + use super::*; + + fn project_renamed_response() -> ApiResponse { + ApiResponse { + status: 302, + headers: vec!["content-type: application/json".to_owned()], + body: Some( + br#"{"slug":"new-project-slug","detail":{"extra":{"url":"/api/0/projects/wat-org/new-project-slug/preprodartifacts/snapshots/upload-options/","slug":"new-project-slug"}}}"# + .to_vec(), + ), + } + } + + #[test] + fn convert_rnf_reports_project_rename() { + let err = project_renamed_response() + .convert_rnf::(ApiErrorKind::ProjectNotFound) + .expect_err("expected a project-renamed error"); + + let source = err.source().map(|s| s.to_string()).unwrap_or_default(); + + assert!( + source.contains("project was renamed to 'new-project-slug'"), + "expected rename message in error source, got: {err:?} / source: {source}" + ); + } +} From e9ee2bf8018d43670f71b41107dc5730cf63cd0f Mon Sep 17 00:00:00 2001 From: Nico Hinderling Date: Mon, 22 Jun 2026 15:31:37 -0700 Subject: [PATCH 2/3] fix(snapshots): Show clear error when project slug was renamed --- src/api/mod.rs | 21 +++++++++++++++--- src/commands/snapshots/upload.rs | 7 +++--- .../snapshots-upload-renamed-project.trycmd | 15 +++++++++++++ .../_fixtures/snapshots/snapshot.png | Bin 0 -> 75 bytes tests/integration/snapshots.rs | 19 +++++++++++++++- 5 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 tests/integration/_cases/snapshots/snapshots-upload-renamed-project.trycmd create mode 100644 tests/integration/_fixtures/snapshots/snapshot.png diff --git a/src/api/mod.rs b/src/api/mod.rs index ce98f49733..c45efd7a0c 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1015,7 +1015,7 @@ impl AuthenticatedApi<'_> { org: &str, project: &str, body: &S, - ) -> ApiResult { + ) -> ApiResult { let path = format!( "/projects/{}/{}/preprodartifacts/snapshots/", PathArg(org), @@ -1023,7 +1023,8 @@ impl AuthenticatedApi<'_> { ); self.request(Method::Post, &path)? .with_zstd_json_body(body)? - .send() + .send()? + .convert_rnf(ApiErrorKind::ProjectNotFound) } /// Fetches upload options for snapshots. @@ -1037,7 +1038,7 @@ impl AuthenticatedApi<'_> { PathArg(org), PathArg(project) ); - self.get(&path)?.convert() + self.get(&path)?.convert_rnf(ApiErrorKind::ProjectNotFound) } pub fn get_latest_base_snapshot( @@ -2169,4 +2170,18 @@ mod tests { "expected rename message in error source, got: {err:?} / source: {source}" ); } + + #[test] + fn convert_rnf_reports_project_rename_for_create_response() { + let err = project_renamed_response() + .convert_rnf::(ApiErrorKind::ProjectNotFound) + .expect_err("expected a project-renamed error"); + + let source = err.source().map(|s| s.to_string()).unwrap_or_default(); + + assert!( + source.contains("project was renamed to 'new-project-slug'"), + "expected rename message in error source, got: {err:?} / source: {source}" + ); + } } diff --git a/src/commands/snapshots/upload.rs b/src/commands/snapshots/upload.rs index 370d268196..45681a8042 100644 --- a/src/commands/snapshots/upload.rs +++ b/src/commands/snapshots/upload.rs @@ -18,7 +18,7 @@ use serde_json::Value; use sha2::{Digest as _, Sha256}; use walkdir::WalkDir; -use crate::api::{Api, CreateSnapshotResponse, ImageMetadata, SnapshotsManifest}; +use crate::api::{Api, ImageMetadata, SnapshotsManifest}; use crate::config::Config; use crate::utils::args::ArgExt as _; use crate::utils::build_vcs::collect_git_metadata; @@ -207,10 +207,9 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { // POST manifest to API println!("{} Creating snapshot...", style(">").dim()); let api = Api::current(); - let response: CreateSnapshotResponse = api + let response = api .authenticated()? - .create_preprod_snapshot(&org, &project, &manifest)? - .convert()?; + .create_preprod_snapshot(&org, &project, &manifest)?; println!( "{} Created snapshot {} with {} {}", diff --git a/tests/integration/_cases/snapshots/snapshots-upload-renamed-project.trycmd b/tests/integration/_cases/snapshots/snapshots-upload-renamed-project.trycmd new file mode 100644 index 0000000000..bb8ca98280 --- /dev/null +++ b/tests/integration/_cases/snapshots/snapshots-upload-renamed-project.trycmd @@ -0,0 +1,15 @@ +``` +$ sentry-cli snapshots upload tests/integration/_fixtures/snapshots --app-id test-app --no-git-metadata +? failed +> Found 1 image file +> Processing 1 image file +error: Project not found. Ensure that you configured the correct project and organization. + +Caused by: + project was renamed to 'new-project-slug' + Please use this slug in your .sentryclirc file, sentry.properties file or in the CLI --project parameter + +Add --log-level=[info|debug] or export SENTRY_LOG_LEVEL=[info|debug] to see more output. +Please attach the full debug log to all bug reports. + +``` diff --git a/tests/integration/_fixtures/snapshots/snapshot.png b/tests/integration/_fixtures/snapshots/snapshot.png new file mode 100644 index 0000000000000000000000000000000000000000..51c29bd304691958e85c595987c238304d19a55d GIT binary patch literal 75 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqLY^*;Ar-fhf1E$?L0&#hLXwN& X(DnMptIS4!fwByqu6{1-oD!M Date: Mon, 22 Jun 2026 15:41:03 -0700 Subject: [PATCH 3/3] docs: Add changelog entry for snapshots rename error fix --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c4e2c3875..1dc49184bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - (snapshots) Compress preprod snapshot manifest with zstd ([#3336](https://github.com/getsentry/sentry-cli/pull/3336)) +### Fixes + +- (snapshots) Show a clear "project was renamed" error instead of a cryptic JSON parse failure when uploading to a renamed project slug ([#3341](https://github.com/getsentry/sentry-cli/pull/3341)) + ## 3.5.1 ### Internal Changes 🔧