Universal-Debloater-Alliance/universal-android-debloater-next-generation · error

There must be 1 tab after serial

Error message

There must be 1 tab after serial

What it means

The devices function parses output of `adb devices -l`-style lines and expects each device line to contain a tab separating the serial from the status. If a line has no '\t', expect panics with "There must be 1 tab after serial". The library assumes well-formed adb output; any deviating line breaks this invariant.

Solutions

  1. Ensure no daemon-start banner is captured: run `adb start-server` once before calling devices().
  2. Verify the adb binary on PATH is the official platform-tools adb (check `which adb`).
  3. Filter adb output lines before parsing to only those containing '\t'.
  4. Upgrade the library / patch devices() to skip non-device lines instead of expecting a tab.

Example fix

// before
let tab_idx = dev_stat.find('\t').expect("There must be 1 tab after serial");
// after
let Some(tab_idx) = dev_stat.find('\t') else { continue; }; // skip banner/header lines
Defensive patterns

Strategy: validation

Validate before calling

let output = std::process::Command::new("adb").args(["devices"]).output()?;
let has_device_line = String::from_utf8_lossy(&output.stdout)
    .lines().any(|l| l.contains('\t'));

Type guard

fn is_device_line(line: &str) -> bool { line.contains('\t') && !line.starts_with("List of") && !line.trim_start().starts_with('*') }

Try / catch

let devices = std::panic::catch_unwind(|| adb::devices()).unwrap_or_else(|_| { eprintln!("malformed adb output; is adb on PATH?"); Vec::new() });

Prevention

When it happens

Trigger: Calling devices() when `adb devices` emits a line without a tab — e.g. the header lines "List of devices attached" or a trailing "* daemon not running..." message, or `adb` not being the real adb binary on PATH.

Common situations: First adb invocation starting the daemon (status lines interleaved), adb wrappers printing different formatting, custom/aliased adb on PATH, localized adb output.

Related errors


AI-assisted analysis of Universal-Debloater-Alliance/universal-android-debloater-next-generation@64465c850c (2026-09-12). Data as JSON: /api/errors/580618bc988b6e98. Report an issue: GitHub.

Appendix: source

Thrown at crates/uad-core/src/adb.rs:123

    /// - TCP/IP: WIFI, Ethernet, etc...
    /// - Local emulators
    ///
    /// Status can be (but not limited to):
    /// - "unauthorized"
    /// - "device"
    pub fn devices(mut self) -> Result<Vec<(String, String)>, String> {
        self.0.arg("devices");
        Ok(self
            .run()?
            .lines()
            .skip(1) // header
            .map(|dev_stat| {
                let tab_idx = dev_stat
                    // OS-specific?
                    .find('\t')
                    // True on Linux,
                    // no matter if ADB is piped or connected to terminal
                    .expect("There must be 1 tab after serial");
                (
                    // serial
                    dev_stat[..tab_idx].to_string(),
                    // status
                    dev_stat[(tab_idx + 1)..].to_string(),
                )
            })
            .collect())
    }

    /// `version` sub-command
    ///
    /// ## Format
    /// This is just a sample,
    /// we don't know which guarantees are stable (yet):
    /// ```txt
    /// Android Debug Bridge version 1.0.41
    /// Version 34.0.5-debian

View on GitHub (pinned to 64465c850c)