You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust错误处理:为何miette输出格式不一致?

miette库输出格式不一致问题排查

我在使用miette库时遇到输出不一致的问题:传入"good"参数执行程序能得到预期的精美格式化错误输出,但传入"bad"参数时却输出类似调试信息的基础格式,两者差异明显但找不到原因。相关代码、依赖配置及运行输出如下:

相关代码

use std::error::Error;

use miette::{Diagnostic, SourceSpan};
use miette::{NamedSource, Result as MietteResult};
use thiserror::Error;

#[derive(Error, Debug, Diagnostic)]
#[error("oops!")]
#[diagnostic(
    code(oops::my::bad),
    url(docsrs),
    help("try doing it better next time?")
)]
struct MyBad {
    // 用于输出代码片段的源文件
    // 如果不关心文件名,也可以直接用String类型
    #[source_code]
    src: NamedSource,
    // 诊断信息中可包含代码片段高亮
    #[label("This bit here")]
    bad_bit: SourceSpan,
}

fn this_gives_correct_formatting() -> MietteResult<()> {
    let res: Result<(), MyBad> = Err(MyBad {
        src: NamedSource::new("bad_file.rs", "source\n  text\n    here".to_string()),
        bad_bit: (9, 4).into(),
    });

    res?;

    Ok(())
}

fn main() -> Result<(), Box<dyn Error>> {
    if std::env::args().nth(1).unwrap() == "bad" {
        let res: Result<(), MyBad> = Err(MyBad {
            src: NamedSource::new("bad_file.rs", "source\n  text\n    here".to_string()),
            bad_bit: (9, 4).into(),
        });

        dbg!(&res);

        res?;

        Ok(())
    } else if std::env::args().nth(1).unwrap() == "good" {
        let res = this_gives_correct_formatting();

        dbg!(&res);

        res?;

        Ok(())
    } else {
        panic!("Pass either 'good' or 'bad'");
    }
}

Cargo.toml配置

[dependencies]
miette = { version = "5.5.0", features = ["fancy"] }
thiserror = "1.0.39"

运行输出

$ cargo run good
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/rust-play good`
[src/main.rs:50] &res = Err(
    MyBad {
        src: NamedSource {
            name: "bad_file.rs",
            source: "<redacted>",
        ,
        bad_bit: SourceSpan {
            offset: SourceOffset(
                9,
            ),
            length: SourceOffset(
                4,
            ),
        },
    },
)
Error: oops::my::bad (https://docs.rs/rust-play/0.1.0/rust_play/struct.MyBad.html)

  × oops!
   ╭─[bad_file.rs:1:1]
 1 │ source
 2 │   text
   ·   ──┬─
   ·     ╰── This bit here
 3 │     here
   ╰────
  help: try doing it better next time?

$ cargo run bad
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `target/debug/rust-play bad`
[src/main.rs:42] &res = Err(
    MyBad {
        src: NamedSource {
            name: "bad_file.rs",
            source: "<redacted>",
        ,
        bad_bit: SourceSpan {
            offset: SourceOffset(
                9,
            ),
            length: SourceOffset(
                4,
            ),
        },
    },
)
Error: MyBad { src: NamedSource { name: "bad_file.rs", source: "<redacted>", bad_bit: SourceSpan { offset: SourceOffset(9), length: SourceOffset(4) } }

问题原因及解决方法

原因

问题核心在于错误类型的转换差异:

  • good分支中,this_gives_correct_formatting返回MietteResult<()>(本质是Result<(), miette::Error>),调用res?时,miette的错误处理机制会自动触发精美格式化输出。
  • bad分支中,直接使用Result<(), MyBad>,当该错误被向上转换为Box<dyn Error>时,丢失了miette专属的格式化上下文,最终输出的是错误结构体的Debug格式。

解决方法

方法一:将错误包装为MietteResult

修改bad分支中的错误定义,将Result<(), MyBad>转换为MietteResult<()>:

let res: MietteResult<()> = Err(MyBad {
    src: NamedSource::new("bad_file.rs", "source\n  text\n    here".to_string()),
    bad_bit: (9, 4).into(),
}.into());

方法二:修改main函数返回类型为MietteResult

直接将main函数的返回值从Result<(), Box<dyn Error>>改为MietteResult<()>,确保所有错误都通过miette机制处理:

fn main() -> MietteResult<()> {
    if std::env::args().nth(1).unwrap() == "bad" {
        let res: Result<(), MyBad> = Err(MyBad {
            src: NamedSource::new("bad_file.rs", "source\n  text\n    here".to_string()),
            bad_bit: (9, 4).into(),
        });

        dbg!(&res);

        res?;

        Ok(())
    } else if std::env::args().nth(1).unwrap() == "good" {
        let res = this_gives_correct_formatting();

        dbg!(&res);

        res?;

        Ok(())
    } else {
        panic!("Pass either 'good' or 'bad'");
    }
}

两种方法都能让"bad"分支的错误输出与"good"分支保持一致的精美格式。

内容的提问来源于stack exchange,提问作者John Graham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 22:30:00