rustdesk/rustdesk · error · anyhow::Error

encoder type mismatch

Error message

encoder type mismatch

What it means

VpxEncoder::new (libs/scrap/src/common/vpxcodec.rs) accepts only EncoderCfg::VPX(config); the catch-all arm returns 'encoder type mismatch'. Same constructor-level variant check pattern used by AomEncoder and HwRamEncoder: the EncoderCfg enum variant must correspond to the concrete encoder type being constructed.

Source

Thrown at libs/scrap/src/common/vpxcodec.rs:170

                        VP9E_SET_TILE_COLUMNS as _,
                        4 as c_int
                    ));
                } else if config.codec == VpxVideoCodecId::VP8 {
                    // https://github.com/webmproject/libvpx/blob/972149cafeb71d6f08df89e91a0130d6a38c4b15/vpx/vp8cx.h#L172
                    // https://groups.google.com/a/webmproject.org/g/webm-discuss/c/DJhSrmfQ61M
                    call_vpx!(vpx_codec_control_(&mut ctx, VP8E_SET_CPUUSED as _, 12,));
                }

                Ok(Self {
                    ctx,
                    width: config.width as _,
                    height: config.height as _,
                    id: config.codec,
                    i444,
                    yuvfmt: Self::get_yuvfmt(config.width, config.height, i444),
                })
            }
            _ => Err(anyhow!("encoder type mismatch")),
        }
    }

    fn encode_to_message(&mut self, input: EncodeInput, ms: i64) -> ResultType<VideoFrame> {
        let mut frames = Vec::new();
        for ref frame in self
            .encode(ms, input.yuv()?, STRIDE_ALIGN)
            .with_context(|| "Failed to encode")?
        {
            frames.push(VpxEncoder::create_frame(frame));
        }
        for ref frame in self.flush().with_context(|| "Failed to flush")? {
            frames.push(VpxEncoder::create_frame(frame));
        }

        // to-do: flush periodically, e.g. 1 second
        if frames.len() > 0 {
            Ok(VpxEncoder::create_video_frame(self.id, frames))

View on GitHub (pinned to 7aa98d43cf)

Solutions

  1. Route only EncoderCfg::VPX to VpxEncoder; check the creation dispatch (codec id -> EncoderCfg variant -> encoder struct).
  2. Make the dispatch match exhaustive over EncoderCfg so the compiler flags missing routes.
  3. Add a regression test per codec id asserting the returned encoder's type.

Example fix

// before
let enc = VpxEncoder::new(cfg, i444)?; // cfg is EncoderCfg::AOM -> 'encoder type mismatch'

// after
match cfg {
    EncoderCfg::VPX(c) => Box::new(VpxEncoder::new(EncoderCfg::VPX(c), i444)?),
    EncoderCfg::AOM(c) => Box::new(AomEncoder::new(EncoderCfg::AOM(c), i444)?),
    EncoderCfg::HWRAM(c) => Box::new(HwRamEncoder::new(EncoderCfg::HWRAM(c), i444)?),
}
Defensive patterns

Strategy: type-guard

Validate before calling

if !matches!(cfg, EncoderCfg::VPX(_)) {
    return Err(anyhow!("VpxEncoder requires EncoderCfg::VPX"));
}

Type guard

fn is_vpx_cfg(cfg: &EncoderCfg) -> bool {
    matches!(cfg, EncoderCfg::VPX(_))
}

Prevention

When it happens

Trigger: Constructing VpxEncoder with EncoderCfg::AOM or EncoderCfg::HWRAM — dispatch layer mapped the negotiated codec (AV1 or hardware) to the libvpx encoder struct.

Common situations: Codec-selection refactors; new EncoderCfg variants added without updating the match in the creation layer; defaults that assume VPX everywhere.

Related errors


AI-assisted analysis of rustdesk/rustdesk@7aa98d43cf (2026-08-16). Data as JSON: /api/errors/bc420c4ef17cb5de. Report an issue: GitHub.