{"record":{"id":"8e34f163ddd33bb2","repo":"dbt-labs/dbt-core","slug":"warning-should-retain-its-fserror","errorCode":null,"errorMessage":"warning should retain its FsError","messagePattern":"warning should retain its FsError","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/dbt-parser/src/resolve/resolve_macros.rs","lineNumber":752,"sourceCode":"\n                let previous_record_count = log_records.lock().unwrap().len();\n                let _ = resolve_docs_macros(&io_args, &assets, None)?;\n                let records = log_records.lock().unwrap();\n                let warnings = &records[previous_record_count..];\n                assert_eq!(\n                    warnings.len(),\n                    case.expected_warning_paths.len(),\n                    \"expected one warning for case {}\",\n                    case.name\n                );\n                for (warning, expected_path) in\n                    warnings.iter().zip(case.expected_warning_paths.iter())\n                {\n                    assert_eq!(warning.severity_number, SeverityNumber::Warn);\n                    let warning = warning\n                        .attributes\n                        .downcast_ref::<FsErrorLog>()\n                        .expect(\"warning should retain its FsError\");\n                    assert_eq!(warning.get_fs_error().code, case.expected_code);\n                    assert_eq!(\n                        warning\n                            .get_fs_error()\n                            .location\n                            .as_ref()\n                            .map(|loc| loc.file.as_ref().clone()),\n                        Some(PathBuf::from(expected_path)),\n                        \"expected warning location for case {}\",\n                        case.name\n                    );\n                }\n            }\n\n            // Positive case\n            let valid_path = PathBuf::from(\"models/valid_doc.md\");\n            fs::write(\n                base_path.join(&valid_path),","sourceCodeStart":734,"sourceCodeEnd":770,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-parser/src/resolve/resolve_macros.rs#L734-L770","documentation":"This is a test assert in dbt-parser's macro-resolution tests: it panics with \"warning should retain its FsError\" when a warning emitted during markdown doc parsing fails to downcast its log attributes to FsErrorLog. The parser contract requires filesystem warnings to carry the structured FsError payload so callers can inspect error codes and locations; the test guards that contract.","triggerScenarios":"Running invalid_markdown_doc_reports_warning_and_continues when resolve_macros emits a warning whose attributes do not contain an FsErrorLog (i.e., the warning path in resolve_macros.rs was changed to log via a plain message instead of FsErrorLog::new(...)).","commonSituations":"A contributor refactors warning emission in resolve_macros and swaps FsErrorLog for a generic log attribute; a middleware/telemetry layer strips or replaces the attributes map before the assertion runs.","solutions":["Locate the warning emission for invalid markdown docs in resolve_macros.rs and ensure it attaches FsErrorLog (with correct code and location) to the log attributes.","Check that FsErrorLog still implements the expected attributes trait (e.g., via extend_as_attributes) and was not changed to a plain string.","Re-run the single test with `cargo test -p dbt-parser invalid_markdown_doc` after the fix."],"exampleFix":"// before\nwarn!(\"invalid markdown doc: {}\", err);\n// after\nwarn!(error = %FsErrorLog::new(err.clone()), \"invalid markdown doc\");","handlingStrategy":"type-guard","validationCode":"// before asserting, check the attribute type\nif warning.attributes.downcast_ref::<FsErrorLog>().is_none() {\n    panic!(\"warning missing FsErrorLog payload: {:?}\", warning.attributes);\n}","typeGuard":"fn as_fs_error_log(attrs: &dyn std::any::Any) -> Option<&FsErrorLog> { attrs.downcast_ref::<FsErrorLog>() }","tryCatchPattern":"// Rust panics abort the test; catch in integration harnesses with catch_unwind\nlet result = std::panic::catch_unwind(|| run_parse_with_warnings());","preventionTips":["Always emit filesystem warnings through FsErrorLog so the payload survives","Add a unit test asserting FsErrorLog attachment for every warning site","Avoid middleware that rewrites log attributes"],"tags":["rust","test-assertion","logging","parser"],"backgroundTag":"internal-invariant-violation","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}