[Bug][Backend] InfluxDB health check throws ArgumentException (duplicate 'write_successful' key) on query failure — masks real error #490

Closed
opened 2026-07-12 00:34:49 +00:00 by spikerj · 1 comment
Owner

Summary

InfluxDB_HealthCheck.TestWriteAndQuery throws System.ArgumentException: An item with the same key has already been added. Key: write_successful whenever the write succeeds but the query step then throws. The exception escapes the check, so the InfluxDB health check reports a misleading "InfluxDB health check failed" (the ArgumentException) instead of the real underlying error — masking genuine InfluxDB problems (see #483).

Evidence (Seq)

Health check InfluxDB with status Unhealthy ... 'InfluxDB health check failed'
System.ArgumentException: An item with the same key has already been added. Key: write_successful
  at SpikerSoft.Api.Infrastructure.HealthChecks.InfluxDB_HealthCheck.TestWriteAndQuery(...)
  at ...InfluxDB_HealthCheck.CheckHealthAsync(...)

Root cause (code)

SpikerSoft.Api/Infrastructure/HealthChecks/InfluxDB_HealthCheck.cs:

  • Line 203 (try, after a successful write): healthData.Add("write_successful", writeResponse.IsSuccessStatusCode);
  • Line 225 (try): healthData.Add("query_successful", queryResponse.IsSuccessStatusCode);
  • Lines 233-234 (catch):
    healthData.Add("write_successful", false);
    healthData.Add("query_successful", false);
    

If the write succeeds (line 203 runs) and the query PostAsync throws (timeout / cancellation / connection reset — plausible given the InfluxDB token issues in #483), control enters the catch and calls healthData.Add("write_successful", false) for a key that is already present -> Dictionary.Add throws ArgumentException. The real exception (ex) is lost.

Fix

Use idempotent indexer assignment in the catch (and ideally throughout) instead of .Add:

catch (Exception ex)
{
    healthData["write_successful"] = false;   // indexer: overwrite-safe
    healthData["query_successful"] = false;
    errors.Add($"Read/write test failed: {ex.Message}");
}

This lets the check surface the actual failure (the ex.Message) instead of a spurious ArgumentException.

Impact

  • Corrupts the InfluxDB health signal (false "health check failed"), contributing to the Unhealthy/Degraded flaps observed while investigating #483.
  • Hides the real InfluxDB error, hindering diagnosis.

Priority: low severity, high confidence / trivial fix. Related: #483.


Filed proactively by automated health check (Seq error audit).

## Summary `InfluxDB_HealthCheck.TestWriteAndQuery` throws `System.ArgumentException: An item with the same key has already been added. Key: write_successful` whenever the write succeeds but the **query step then throws**. The exception escapes the check, so the InfluxDB health check reports a misleading `"InfluxDB health check failed"` (the ArgumentException) instead of the real underlying error — masking genuine InfluxDB problems (see #483). ## Evidence (Seq) ``` Health check InfluxDB with status Unhealthy ... 'InfluxDB health check failed' System.ArgumentException: An item with the same key has already been added. Key: write_successful at SpikerSoft.Api.Infrastructure.HealthChecks.InfluxDB_HealthCheck.TestWriteAndQuery(...) at ...InfluxDB_HealthCheck.CheckHealthAsync(...) ``` ## Root cause (code) `SpikerSoft.Api/Infrastructure/HealthChecks/InfluxDB_HealthCheck.cs`: - Line 203 (try, after a successful write): `healthData.Add("write_successful", writeResponse.IsSuccessStatusCode);` - Line 225 (try): `healthData.Add("query_successful", queryResponse.IsSuccessStatusCode);` - Lines 233-234 (catch): ```csharp healthData.Add("write_successful", false); healthData.Add("query_successful", false); ``` If the write succeeds (line 203 runs) and the **query `PostAsync` throws** (timeout / cancellation / connection reset — plausible given the InfluxDB token issues in #483), control enters the catch and calls `healthData.Add("write_successful", false)` for a key that is **already present** -> `Dictionary.Add` throws `ArgumentException`. The real exception (`ex`) is lost. ## Fix Use idempotent indexer assignment in the catch (and ideally throughout) instead of `.Add`: ```csharp catch (Exception ex) { healthData["write_successful"] = false; // indexer: overwrite-safe healthData["query_successful"] = false; errors.Add($"Read/write test failed: {ex.Message}"); } ``` This lets the check surface the actual failure (the `ex.Message`) instead of a spurious ArgumentException. ## Impact - Corrupts the InfluxDB health signal (false "health check failed"), contributing to the Unhealthy/Degraded flaps observed while investigating #483. - Hides the real InfluxDB error, hindering diagnosis. Priority: low severity, **high confidence / trivial fix**. Related: #483. --- _Filed proactively by automated health check (Seq error audit)._
Author
Owner

Resolved in spikersoft-backend PR #213 (merged to master). Both instances of the key-collision class fixed: (1) TestWriteAndQuery's catch now uses indexer assignment and preserves a successful write's recorded value, so write-succeeds-query-throws surfaces the REAL InfluxDB error instead of ArgumentException; (2) a latent second instance found during testing — CheckPingEndpoint's GetValues(X-Influxdb-Version) throws when a proxy strips the header, and its catch double-added ping_available — now TryGetValues + indexer, with ready/bucket catches hardened to match. 4 new xUnit tests including the exact #483-shaped failure. After CI rolls the API, the InfluxDB health check will report the genuine underlying failure for #483. Closing.

Resolved in spikersoft-backend PR #213 (merged to master). Both instances of the key-collision class fixed: (1) TestWriteAndQuery's catch now uses indexer assignment and preserves a successful write's recorded value, so write-succeeds-query-throws surfaces the REAL InfluxDB error instead of ArgumentException; (2) a latent second instance found during testing — CheckPingEndpoint's GetValues(X-Influxdb-Version) throws when a proxy strips the header, and its catch double-added ping_available — now TryGetValues + indexer, with ready/bucket catches hardened to match. 4 new xUnit tests including the exact #483-shaped failure. After CI rolls the API, the InfluxDB health check will report the genuine underlying failure for #483. Closing.
Sign in to join this conversation.