Skip to content

Discarding the original error while constructing another error #10

Open

Description

@cblanquera

Timing: Follow-up after trial/3 merges into main; defer implementation until then.

Review baseline: Local trial/3 at a094418baf6388e3eeca23821df481a7f0a8751c. This branch is not yet on the remote. Source locations below refer to that snapshot and should be rechecked after merge.

Problem

Configuration error mapping replaces underlying errors with generic messages and drops the original causes. This removes useful developer diagnostics even though the framework supports separate sanitized public messages and private source chains.

Evidence

  • crates/server/src/config.rs:88-89: serde_json::from_str(...).map_err(|_| ...) discards parse category and location.
  • crates/server/src/config.rs:234-236: defaults serialization similarly drops its cause.
  • A controlled malformed-JSON probe returned invalid configuration JSON at review with Error::source() == None.

Acceptance criteria

  • Retain original parse/serialization causes when adding framework context.
  • Preserve safe public messages and avoid automatically exposing configuration values.
  • Audit analogous wrapping sites for unjustified cause loss; retain deliberate redaction where required and document the reason.
  • Verify that private source traversal preserves relevant diagnostic information while public output remains sanitized.

Code examples and suggested direction

Preserve the sanitized outer message and retain the original private cause:

let value: serde_json::Value = serde_json::from_str(text).map_err(|cause| {
    Error::invalid("invalid configuration JSON")
        .at_path(label)
        .with_cause(cause)
})?;

Apply the same pattern to defaults serialization where appropriate. Keeping a cause is distinct from disclosing its text through public Display/wire fields.

Activity

  1. cblanquera commented on Oct 26, 2026

    @cblanquera
    MemberAuthor

    Suggested investigation and fix notes

    Deferred until trial/3 is merged into main. Recheck the merged source and tests first. The snippets are examples/proposals, not an approved patch or a change to frozen contracts.

    1. Begin with the two configuration mappings identified in the issue. Search analogous map_err(|_| ...) sites, but distinguish deliberate error classification/redaction from accidental cause loss.
    2. Attach the concrete original error with with_cause while preserving existing category, path, status, origin, and sanitized outer text. Avoid turning the source into a formatted string.
    3. Add a malformed-JSON case that downcasts the retained source and inspects category and line/column. Exercise a custom serializer that deliberately fails for the defaults path.
    4. Verify ordinary non-verbose CLI output stays sanitized. Explicit developer diagnostics may inspect the source; never automatically place raw configuration values in public envelopes.
    5. Coordinate with Duplicating an underlying error in both the wrapper message and its source #11 so newly preserved causes are rendered once with useful context.

    Example assertion using current public APIs after the fix:

    use std::error::Error as _;
    
    let mut layers = stackpress_server::ConfigLayers::new();
    let error = layers.json("file", "{\n  \"secret\": }").err().unwrap();
    let source = error.source().unwrap()
        .downcast_ref::<serde_json::Error>().unwrap();
    assert!(source.is_syntax());
    assert_eq!(source.line(), 2);
    assert_eq!(error.path(), Some("file"));
    assert_eq!(error.public_view().error, "invalid configuration JSON");

    Place regression coverage with configuration construction/CLI entry contracts. Start with cargo test -p stackpress-server --test construction --locked and cargo test -p stackpress-cli --test entry_contracts --locked.

    Implementation workflow: After the merge, follow .agents/workflows/rust-programming.md: prove the affected behavior, complete the three test-verified review rounds, and record relevant formatting/lints/docs, feature/platform scope, and applicable development coverage. Preserve unrelated changes.

  2. cblanquera commented on Oct 26, 2026

    @cblanquera
    MemberAuthor

    Fixed on trial/3 in 407b4d6 + df443b7 (merged as ff7a251, task 00010 lane 2; not yet on main, so leaving open).

    Coordinator-verified on the combined code: fmt, Clippy -D warnings, Rustdoc -D warnings, cargo +1.96.0 check, 466 workspace tests and 857 doctests pass (467 tests on merged trial/3). Coverage: server 91.61%, CLI 93.15%, transformer 93.62%.

  3. added a commit that references this issue on Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions