Real latent NRE found via CS8604 triage in the RPC-reply infrastructure.
The PublishReplyAsync(object payload, ...) helper in the RPC consumer hosted services serializes the reply with:
var body = JsonSerializer.SerializeToUtf8Bytes(payload, payload.GetType(), JsonOptions);
payload.GetType() throws NullReferenceException when payload is null.
In DecompileRpcConsumerHostedService and NotificationsRpcConsumerHostedService, the payload comes from the non-genericmediator.Send(object request) overload, which returns Task<object?> — genuinely nullable. If an RPC handler returns null, PublishReplyAsync(null, ...) NREs at payload.GetType(). The reply is never published (the RPC caller waits and times out), the BasicAckAsync after it is skipped, and the message is nackd/redelivered into the same crash (poison-message loop until it hits the DLQ).
Reachability: conditional on an RPC handler returning null. Confirmed the compiler sees response as nullable at both call sites (CS8604 at DecompileRpcConsumerHostedService.cs:151 and NotificationsRpcConsumerHostedService.cs:169). EmbeddingsRpcConsumerHostedService and PassportOcrConsumerHostedService share the identical payload.GetType() pattern but currently receive a non-null typed response (latent, not yet reachable).
Proposed fix: guard null in PublishReplyAsync (matching the existing early-return style for a missing replyTo):
if (payload is null)
{
_logger.LogWarning("Null RPC response; cannot publish reply (correlation={CorrelationId})", correlationId);
return; // or publish an explicit error envelope
}
Apply to all four consumers for defensiveness (Decompile + Notifications are the reachable ones; Embeddings + PassportOcr are hardening). SonarQube rule external_roslyn:CS8604.
Status: fix is ready to implement; holding the PR only because the multi-arch CI queue is currently ~3 PRs deep on the arm64 Jetson runners and this touches 2-4 workers. Will open the PR once the queue drains.
**Real latent NRE found via CS8604 triage** in the RPC-reply infrastructure.
The `PublishReplyAsync(object payload, ...)` helper in the RPC consumer hosted services serializes the reply with:
```
var body = JsonSerializer.SerializeToUtf8Bytes(payload, payload.GetType(), JsonOptions);
```
`payload.GetType()` throws **NullReferenceException** when `payload` is null.
In `DecompileRpcConsumerHostedService` and `NotificationsRpcConsumerHostedService`, the payload comes from the **non-generic** `mediator.Send(object request)` overload, which returns `Task<object?>` — genuinely nullable. If an RPC handler returns null, `PublishReplyAsync(null, ...)` NREs at `payload.GetType()`. The reply is never published (the RPC caller waits and times out), the `BasicAckAsync` after it is skipped, and the message is nackd/redelivered into the same crash (poison-message loop until it hits the DLQ).
**Reachability:** conditional on an RPC handler returning null. Confirmed the compiler sees `response` as nullable at both call sites (CS8604 at DecompileRpcConsumerHostedService.cs:151 and NotificationsRpcConsumerHostedService.cs:169). `EmbeddingsRpcConsumerHostedService` and `PassportOcrConsumerHostedService` share the identical `payload.GetType()` pattern but currently receive a non-null typed response (latent, not yet reachable).
**Proposed fix:** guard null in `PublishReplyAsync` (matching the existing early-return style for a missing `replyTo`):
```
if (payload is null)
{
_logger.LogWarning("Null RPC response; cannot publish reply (correlation={CorrelationId})", correlationId);
return; // or publish an explicit error envelope
}
```
Apply to all four consumers for defensiveness (Decompile + Notifications are the reachable ones; Embeddings + PassportOcr are hardening). SonarQube rule external_roslyn:CS8604.
**Status:** fix is ready to implement; holding the PR only because the multi-arch CI queue is currently ~3 PRs deep on the arm64 Jetson runners and this touches 2-4 workers. Will open the PR once the queue drains.
Resolved in spikersoft-backend PR #371 (merged to master). Guarded null handler response before the payload.GetType() deref in the Decompile, Notifications, and Embeddings RPC consumers so a null mediator.Send result no longer NREs the reply path. Closing.
Resolved in spikersoft-backend PR #371 (merged to `master`). Guarded null handler response before the payload.GetType() deref in the Decompile, Notifications, and Embeddings RPC consumers so a null mediator.Send result no longer NREs the reply path. Closing.
Resolved in spikersoft-backend PR #366 (merged to master). Guarded null handler response in PublishReplyAsync across 3 RPC consumers (Decompile/Notifications/Embeddings) so a null mediator.Send result no longer NREs at payload.GetType() (CS8604). Build clean. All build/test contexts green; merged past the non-blocking notify job. Closing.
Resolved in spikersoft-backend PR #366 (merged to `master`). Guarded null handler response in PublishReplyAsync across 3 RPC consumers (Decompile/Notifications/Embeddings) so a null mediator.Send result no longer NREs at payload.GetType() (CS8604). Build clean. All build/test contexts green; merged past the non-blocking notify job. Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Real latent NRE found via CS8604 triage in the RPC-reply infrastructure.
The
PublishReplyAsync(object payload, ...)helper in the RPC consumer hosted services serializes the reply with:payload.GetType()throws NullReferenceException whenpayloadis null.In
DecompileRpcConsumerHostedServiceandNotificationsRpcConsumerHostedService, the payload comes from the non-genericmediator.Send(object request)overload, which returnsTask<object?>— genuinely nullable. If an RPC handler returns null,PublishReplyAsync(null, ...)NREs atpayload.GetType(). The reply is never published (the RPC caller waits and times out), theBasicAckAsyncafter it is skipped, and the message is nackd/redelivered into the same crash (poison-message loop until it hits the DLQ).Reachability: conditional on an RPC handler returning null. Confirmed the compiler sees
responseas nullable at both call sites (CS8604 at DecompileRpcConsumerHostedService.cs:151 and NotificationsRpcConsumerHostedService.cs:169).EmbeddingsRpcConsumerHostedServiceandPassportOcrConsumerHostedServiceshare the identicalpayload.GetType()pattern but currently receive a non-null typed response (latent, not yet reachable).Proposed fix: guard null in
PublishReplyAsync(matching the existing early-return style for a missingreplyTo):Apply to all four consumers for defensiveness (Decompile + Notifications are the reachable ones; Embeddings + PassportOcr are hardening). SonarQube rule external_roslyn:CS8604.
Status: fix is ready to implement; holding the PR only because the multi-arch CI queue is currently ~3 PRs deep on the arm64 Jetson runners and this touches 2-4 workers. Will open the PR once the queue drains.
Resolved in spikersoft-backend PR #371 (merged to
master). Guarded null handler response before the payload.GetType() deref in the Decompile, Notifications, and Embeddings RPC consumers so a null mediator.Send result no longer NREs the reply path. Closing.Resolved in spikersoft-backend PR #366 (merged to
master). Guarded null handler response in PublishReplyAsync across 3 RPC consumers (Decompile/Notifications/Embeddings) so a null mediator.Send result no longer NREs at payload.GetType() (CS8604). Build clean. All build/test contexts green; merged past the non-blocking notify job. Closing.