elsa-workflows/elsa-core · critical · DocumentStoreValidationException

Stored secret document

Error message

Stored secret document '{document.Id}' could not be deserialized.

What it means

When loading a stored secret document, the repository JSON-deserializes the stored Content into a Secret using its configured serializer options. If the JSON is null/corrupt or does not deserialize to a Secret, it throws DocumentStoreValidationException. This protects callers from silently receiving a null Secret from damaged storage data.

Solutions

  1. Inspect the stored document Content in the database and fix or remove the corrupt row.
  2. Re-create the affected secret (delete the bad document, then add the secret again).
  3. Check for a version mismatch: data written by an older/newer Elsa version may need migration.
  4. Restore the document from a backup if the value cannot be reconstructed.
Defensive patterns

Strategy: try-catch

Validate before calling

// If you own the stored content, pre-check it:
try { using var _ = JsonDocument.Parse(content); } catch (JsonException) { throw new InvalidOperationException("Stored secret JSON is invalid."); }

Type guard

bool IsValidStoredSecretJson(string content) { try { return JsonSerializer.Deserialize<JsonElement>(content).ValueKind == JsonValueKind.Object; } catch (JsonException) { return false; } }

Try / catch

try { var secret = await secretRepository.GetAsync(id, ct); }
catch (DocumentStoreValidationException ex) { logger.LogError(ex, "Corrupt secret document {Id}", id); /* skip, repair, or fail fast */ }

Prevention

When it happens

Trigger: Calling GetAsync (or any read path via LoadDocumentAsync) on a stored document whose Content was written by an incompatible serializer version, manually edited, truncated, or whose schema no longer matches the current Secret type.

Common situations: Upgrading Elsa between versions where the stored Secret JSON schema changed; DB rows edited by hand or by external tooling; a migration or backup/restore that corrupted document content.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/1c962036b4bc03cd. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Secrets.Persistence.VNext/Repositories/VNextSecretRepository.cs:133

            StorageUnitName,
            NormalizeDocumentId(secret.Name),
            JsonSerializer.Serialize(secret, _jsonOptions),
            CreateIndexValues(secret),
            expectedVersion);

        await documentStore.SaveAsync(request, cancellationToken);
    }

    private async Task<(StoredDocument Document, Secret Secret)?> LoadDocumentAsync(string name, CancellationToken cancellationToken)
    {
        var document = await documentStore.LoadAsync(StorageUnitName, NormalizeDocumentId(name), cancellationToken);
        return document is null ? null : (document, Deserialize(document));
    }

    private Secret Deserialize(StoredDocument document)
    {
        return JsonSerializer.Deserialize<Secret>(document.Content, _jsonOptions)
            ?? throw new DocumentStoreValidationException($"Stored secret document '{document.Id}' could not be deserialized.");
    }

    private static Dictionary<string, string?> CreateIndexValues(Secret secret)
    {
        return new()
        {
            [nameof(Secret.Name)] = secret.Name,
            [nameof(Secret.TypeName)] = secret.TypeName,
            [nameof(Secret.StoreName)] = secret.StoreName,
            [nameof(Secret.Scope)] = secret.Scope,
            [nameof(Secret.Status)] = secret.Status.ToString()
        };
    }

    private static string NormalizeDocumentId(string name)
    {
        return name.Trim().ToLowerInvariant();
    }

View on GitHub (pinned to fe9217bdfa)