Skip to content

fix(multipart): Use correct discard reasons#5950

Open
elramen wants to merge 4 commits intomasterfrom
elramen-minidump-outcomes
Open

fix(multipart): Use correct discard reasons#5950
elramen wants to merge 4 commits intomasterfrom
elramen-minidump-outcomes

Conversation

@elramen
Copy link
Copy Markdown
Member

@elramen elramen commented May 6, 2026

Use correct discard reasons for outcomes across multipart endpoints. Also refactor from Vec<Managed<Item>> to Managed<Items> to simplify "all-item"-operations; albeit with a tradeoff of less ergonomic operations on individual items (see the indexing used to access and modify the minidump and proserpodump).

@elramen elramen force-pushed the elramen-minidump-outcomes branch 2 times, most recently from bab71e8 to 3ba99b0 Compare May 6, 2026 15:29
@elramen elramen force-pushed the elramen-minidump-outcomes branch from 3ba99b0 to c055532 Compare May 6, 2026 15:32
@elramen elramen marked this pull request as ready for review May 6, 2026 15:40
@elramen elramen requested a review from a team as a code owner May 6, 2026 15:40
elramen

This comment was marked as off-topic.

@elramen elramen force-pushed the elramen-minidump-outcomes branch from ae96e45 to d4025f1 Compare May 6, 2026 15:52
Comment on lines +127 to +129
let item_type = DiscardItemType::Attachment(DiscardAttachmentType::Minidump);
let _ = items.reject_err(Outcome::Invalid(DiscardReason::TooLarge(item_type)));
return Err(BadStoreRequest::Overflow(item_type));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since ownership of the items is not passed here, I would also not reject it, this pattern makes it easy to emit outcomes twice accidentally. In practice Managed has an internal guard against that, but the intention was more to guard against bugs.

How does it look like if we return a better error here, which implements OutcomeError and then the caller can use reject on the result. Like here.

Also fine to explore in a follow-up but in general I think we should stick to that pattern (maybe should force it with making reject_err take &mut self).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I'll look into it!

Comment on lines +193 to +204
let prosperodump_idx = items
.iter()
.position(|item| item.attachment_type() == Some(AttachmentType::Prosperodump))
.ok_or(BadStoreRequest::MissingProsperodump)
.inspect_err(|_| {
let _ = items.reject_err(Outcome::Invalid(DiscardReason::MissingProsperodumpUpload));
})?;
let payload = items[prosperodump_idx].payload();
validate_prosperodump(&payload, &items)?;
items.modify(|items, _| {
items[prosperodump_idx].set_payload(OctetStream, payload);
});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this be one big try_modify which does the error handling and you don't need to maintain an index?

We just might need better errors that implement OutcomeError or implement it on BadStoreRequest, although I'd prefer more and better scoped errors which then convert to BadStoreRequest.

Relay could use some better error handling in general.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Comment on lines +56 to +60
let envelope = items.map(|items, records| {
if items.iter().any(|i| i.creates_event()) {
records.modify_by(DataCategory::Error, 1);
}
Box::new(Envelope::from_request(Some(path.event_id), meta).with_items(items))
Copy link
Copy Markdown
Member Author

@elramen elramen May 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Steered away from a common envelope-creation function because of the complexity of keeping records correct in all cases. Opened #5949 to address this

Comment thread relay-server/src/endpoints/minidump.rs Outdated
Comment thread relay-server/src/endpoints/minidump.rs Outdated
// Doing these operations does not make sense if we already streamed the minidump to objectstore.
if !minidump_item.is_attachment_ref() {
let payload = minidump_item.payload();
if !items[minidump_idx].is_attachment_ref() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed offline, this should become easier if you do the .find() inside a try_modify.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit aa1370c. Configure here.

};
Some(Outcome::Invalid(discard_reason))
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MissingProsperodump missing from to_outcome match

High Severity

BadStoreRequest::to_outcome() maps MissingMinidump to DiscardReason::MissingMinidumpUpload but has no arm for MissingProsperodump, causing it to fall through to the _ => DiscardReason::Internal wildcard. The playstation endpoint relies on this mapping via .reject(&items)?, so missing prosperodump requests will emit "internal" instead of "missing_prosperodump_upload" as the discard reason.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit aa1370c. Configure here.

Comment on lines +129 to +139
let discard_reason = match self {
Self::InvalidCompressionContainer(_) => DiscardReason::InvalidCompression,
Self::InvalidMinidump => DiscardReason::InvalidMinidump,
Self::InvalidProsperodump => DiscardReason::InvalidProsperodump,
Self::MissingMinidump => DiscardReason::MissingMinidumpUpload,
Self::Overflow(item_type) => DiscardReason::TooLarge(*item_type),
_ => DiscardReason::Internal,
};
Some(Outcome::Invalid(discard_reason))
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The to_outcome() function doesn't handle BadStoreRequest::MissingProsperodump, causing it to report DiscardReason::Internal instead of the more specific DiscardReason::MissingProsperodumpUpload.
Severity: MEDIUM

Suggested Fix

Add a match arm to the to_outcome() function to map BadStoreRequest::MissingProsperodump to DiscardReason::MissingProsperodumpUpload. This will ensure that missing prosperodump files are categorized correctly.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: relay-server/src/endpoints/common.rs#L127-L139

Potential issue: The `to_outcome()` function is missing a match arm for the
`BadStoreRequest::MissingProsperodump` error. When a PlayStation crash upload request is
missing the required `prosperodump` file, this error is generated. However, instead of
being mapped to the specific `DiscardReason::MissingProsperodumpUpload`, it falls
through to the wildcard `_` arm, which incorrectly reports the outcome as
`DiscardReason::Internal`. This miscategorizes a client-side upload error as an internal
server error, hindering correct monitoring of PlayStation crash reports.

Also affects:

  • relay-server/src/endpoints/playstation.rs:195
  • relay-server/src/services/outcome.rs:381

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants