facebook/flow · error

only 7bit ascii allowed in {}

Error message

only 7bit ascii allowed in {}

What it means

flow_lsp::file_url::create() converts a filesystem path into a file:// URI by percent-encoding every character not in PATH_SAFE_CHARS. encode() can only emit %XX escapes for code points in printable 7-bit ASCII (32..=127); any other character — an accented letter, CJK character, emoji, or a control char — hits this panic. So merely opening a document whose absolute path contains non-ASCII text crashes the conversion instead of producing a URI.

Source

Thrown at rust_port/crates/flow_lsp/src/file_url.rs:59

        Err(err)
    } else if cfg!(windows) {
        Ok(s.replace('/', "\\"))
    } else {
        Ok(s)
    }
}

fn encode(safe_chars: &str, s: &str) -> String {
    let mut buf = String::with_capacity(s.len() * 2);
    for c in s.chars() {
        if cfg!(windows) && c == '\\' {
            buf.push('/');
        } else if safe_chars.contains(c) {
            buf.push(c);
        } else {
            let code = c as u32;
            if !(32..=127).contains(&code) {
                panic!("only 7bit ascii allowed in {}", s);
            }
            buf.push_str(&format!("%{code:02X}"));
        }
    }
    buf
}

pub fn parse(uri: &str) -> Result<String, String> {
    let caps = URL_RE
        .captures(uri)
        .ok_or_else(|| format!("not a file url - {}", uri))?;
    let host = caps.get(1).unwrap().as_str();
    let path = caps.get(2).unwrap().as_str();
    let query_fragment = caps.get(3).unwrap().as_str();
    let path = decode(path)?;
    if !host.is_empty() && host != "localhost" {
        return Err(format!("not localhost - {}", uri));
    }

View on GitHub (pinned to f88ac94bcf)

Solutions

  1. Move (or symlink) the project to an all-ASCII path and reopen it from there — this is the immediate workaround.
  2. Ensure TMPDIR/HOME and the workspace root are ASCII-only, since derived paths inherit them.
  3. Fix encode() upstream to percent-encode the raw UTF-8 BYTES of each non-ASCII char (RFC 3986) instead of panicking: iterate s.as_bytes() and emit %XX per byte, since code points >= 128 are exactly what the range check rejects today.
  4. Decode side note: parse()/decode() has the same 7-bit restriction, so keep the fix symmetric if you patch both.

Example fix

// before (flow_lsp/src/file_url.rs)
let code = c as u32;
if !(32..=127).contains(&code) {
    panic!("only 7bit ascii allowed in {}", s);
}
buf.push_str(&format!("%{code:02X}"));

// after: percent-encode raw UTF-8 bytes, RFC 3986 style
for b in c.to_string().as_bytes() {
    buf.push_str(&format!("%{b:02X}"));
}
Defensive patterns

Strategy: validation

Validate before calling

// before file_url::create(path)
if !path.is_ascii() {
    return Err(format!("path contains non-ASCII characters unsupported by file_url: {path}"));
}
let uri = file_url::create(path);

Type guard

fn is_ascii_path(p: &str) -> bool {
    p.is_ascii()
}

Try / catch

let uri = std::panic::catch_unwind(|| file_url::create(path));
match uri {
    Ok(u) => Ok(u),
    Err(_) => Err("file_url only supports 7-bit ASCII paths; relocate the file".into()),
}

Prevention

When it happens

Trigger: Calling file_url::create(path) (directly or through LSP document-open flows) with a path containing any character outside 32..=127: /users/jose/, /home/user/projeto-文档/, emoji in folder names, or control characters in a filename. Windows backslashes are fine (they are converted to '/'); only non-ASCII code points trigger it.

Common situations: Machines with localized usernames (e.g. /Users/josé/); projects checked out into non-ASCII directories; files copied from other OSes keeping Unicode names; CI caches rooted under Unicode paths; tests with Unicode fixtures.

Related errors


AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20). Data as JSON: /api/errors/5b890c95e3c855fe. Report an issue: GitHub.