tonhowtf/omniget · error

nao reconheci um perfil do X em

Error message

nao reconheci um perfil do X em: {}

What it means

analyze builds a ProfileReport for an X account and throws this error when `handle_from` cannot derive a handle from the input. The parser accepts `@name`, bare alphanumeric/underscore handles up to 15 chars, and x.com/twitter.com profile URLs, rejecting reserved paths. The raw input is included in the message.

Solutions

  1. Normalize the input to one of the accepted forms (`@handle`, `handle`, `https://x.com/handle`) before calling analyze
  2. Validate client-side with a regex like ^[A-Za-z0-9_]{1,15}$ on the trimmed, '@'-stripped input and reject early with a clear message
  3. If the input is a tweet URL, call the thread/post tooling instead; if it's a profile URL with extra path segments (e.g. /media), strip to the first path segment

Example fix

// before
let report = analyze(user_text, 50, false).await?;
// after
let handle = user_text.trim().trim_start_matches('@');
if !handle.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') || handle.is_empty() || handle.len() > 15 {
    anyhow::bail!("handle invalido: '{user_text}'");
}
let report = analyze(handle, 50, false).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_x_handle(input: &str) -> bool {
    let s = input.trim().trim_start_matches('@');
    !s.is_empty() && s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') && s.chars().count() <= 15
}
anyhow::ensure!(is_valid_x_handle(user_input), "use @handle, handle ou URL de perfil do X");
let report = analyze(user_input, limit, with_replies).await?;

Type guard

fn as_x_handle(input: &str) -> Option<String> {
    let s = input.trim().trim_start_matches('@');
    match (s.is_empty(), s.chars().count() <= 15, s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')) {
        (false, true, true) => Some(s.to_string()),
        _ => None,
    }
}

Try / catch

match analyze(input, limit, with_replies).await {
    Err(e) if e.to_string().contains("nao reconheci um perfil") => {
        eprintln!("'{}' nao e um perfil do X valido", input);
        Ok(ProfileReport::default())
    }
    Err(e) => Err(e),
    Ok(r) => Ok(r),
}

Prevention

When it happens

Trigger: Calling analyze with an empty string, a display name with spaces, a handle over 15 chars, a tweet/status URL instead of a profile URL, or a URL like https://x.com/i/lists/... that resolves to a reserved segment.

Common situations: User pastes a status permalink expecting a profile report; input collected from a search box containing free text like 'NASA official'; trailing slashes or query strings on a bare handle (`nasa?foo`); copied handle with trailing period or emoji.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/33a5aa4a3d89bf75. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/x/profile.rs:59

    /// Hora local (0–23).
    pub by_hour: Vec<Slot>,
    /// 0 = domingo.
    pub by_weekday: Vec<Slot>,
    pub best_hour: Option<u32>,
    pub best_weekday: Option<u32>,
    pub top_posts: Vec<XPost>,
    pub top_hashtags: Vec<TagCount>,
    pub top_mentions: Vec<TagCount>,
    pub utc_offset_minutes: i32,
}

pub async fn analyze(
    input: &str,
    limit: usize,
    with_replies: bool,
) -> anyhow::Result<ProfileReport> {
    let handle = super::handle_from(input)
        .ok_or_else(|| anyhow!("nao reconheci um perfil do X em: {}", input))?;
    let user = super::fx::profile(&handle).await?;
    let mut posts: Vec<XPost> = Vec::new();
    let mut cursor: Option<String> = None;
    let limit = limit.clamp(20, 1000);
    for _ in 0..40 {
        let page = super::fx::profile_statuses(&handle, cursor.as_deref(), with_replies).await?;
        if page.items.is_empty() {
            break;
        }
        posts.extend(page.items);
        if posts.len() >= limit || page.cursor.is_none() {
            break;
        }
        cursor = page.cursor;
        tokio::time::sleep(std::time::Duration::from_millis(250)).await;
    }
    posts.truncate(limit);
    let posts = super::dedup_posts(posts);

View on GitHub (pinned to 8600b91f42)