{"record":{"id":"10b86e9150362bff","repo":"rustdesk/rustdesk","slug":"no-valid-frame-10b86e","errorCode":null,"errorMessage":"no valid frame","messagePattern":"no valid frame","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"libs/scrap/src/common/vpxcodec.rs","lineNumber":190,"sourceCode":"    }\n\n    fn encode_to_message(&mut self, input: EncodeInput, ms: i64) -> ResultType<VideoFrame> {\n        let mut frames = Vec::new();\n        for ref frame in self\n            .encode(ms, input.yuv()?, STRIDE_ALIGN)\n            .with_context(|| \"Failed to encode\")?\n        {\n            frames.push(VpxEncoder::create_frame(frame));\n        }\n        for ref frame in self.flush().with_context(|| \"Failed to flush\")? {\n            frames.push(VpxEncoder::create_frame(frame));\n        }\n\n        // to-do: flush periodically, e.g. 1 second\n        if frames.len() > 0 {\n            Ok(VpxEncoder::create_video_frame(self.id, frames))\n        } else {\n            Err(anyhow!(\"no valid frame\"))\n        }\n    }\n\n    fn yuvfmt(&self) -> crate::EncodeYuvFormat {\n        self.yuvfmt.clone()\n    }\n\n    #[cfg(feature = \"vram\")]\n    fn input_texture(&self) -> bool {\n        false\n    }\n\n    fn set_quality(&mut self, ratio: f32) -> ResultType<()> {\n        let mut c = unsafe { *self.ctx.config.enc.to_owned() };\n        let (q_min, q_max) = Self::calc_q_values(ratio);\n        c.rc_min_quantizer = q_min;\n        c.rc_max_quantizer = q_max;\n        c.rc_target_bitrate = Self::bitrate(self.width as _, self.height as _, ratio);","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/rustdesk/rustdesk/blob/7aa98d43cf1962a7a29ec16ffef42974377ef11e/libs/scrap/src/common/vpxcodec.rs#L172-L208","documentation":"VpxEncoder::encode_to_message encodes the input AND then calls flush(), collecting all produced frames; if after both steps the list is empty it returns Err('no valid frame'). Because flush() is already drained here (unlike the AOM path), an empty result means the encoder genuinely produced nothing for the input — almost always an invalid input or misconfigured encoder rather than latency.","triggerScenarios":"input.yuv() returning an empty/zero-sized image; encoder width/height mismatched with the submitted frame so libvpx rejects it silently; encoder already in a failed state from an earlier control call.","commonSituations":"Screen capture returning a 0x0 frame during mode changes/monitor hotplug; resolution change after encoder creation without recreating the encoder; corrupted capture buffers.","solutions":["Check the capture source: skip encode when the frame is empty or dimensions are 0 (e.g. during display transitions).","Recreate the encoder whenever the capture width/height changes instead of reusing the old config.","If it fires on the very first frame only, tolerate and continue — but since flush() ran, treat repeated occurrences as an input bug.","Log input dimensions vs encoder config at the error site."],"exampleFix":"// before\nlet vf = enc.encode_to_message(input, ms)?; // empty after encode+flush -> Err\n\n// after: guard the capture side\nlet Ok(yuv) = input.yuv() else { continue; };\nif yuv.dim == (0, 0) { continue; } // display switching, no data yet\nlet vf = enc.encode_to_message(input, ms)?;","handlingStrategy":"validation","validationCode":"let (w, h) = (frame.width(), frame.height());\nif w == 0 || h == 0 { continue; } // display transitioning / hotplug\nif (w, h) != (enc.width as u32, enc.height as u32) { recreate_encoder(w, h)?; }","typeGuard":null,"tryCatchPattern":"match enc.encode_to_message(input, ms) {\n    Ok(vf) => send(vf),\n    Err(e) if e.to_string() == \"no valid frame\" && first_few => continue,\n    Err(e) => return Err(e), // flush already ran: persistent empties mean bad input\n}","preventionTips":["Skip encoding for zero-sized capture frames during display transitions.","Recreate the encoder whenever capture dimensions change.","Because vpxcodec flushes inside encode_to_message, persistent 'no valid frame' points at the input pipeline — instrument capture."],"tags":["encoder","vpx","vp9","video","capture"],"backgroundTag":null,"analyzedSha":"7aa98d43cf1962a7a29ec16ffef42974377ef11e","analyzedAt":"2026-08-16T06:17:34.842Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}