xai-org/grok-build · error · std::io::Error

invalid workflow run id

Error message

invalid workflow run id

What it means

validate_run_id enforces that a workflow run id is non-empty and contains only ASCII alphanumeric characters, '_' or '-'. It returns InvalidInput with this message otherwise. This prevents run ids from escaping their directory (path traversal) or producing unusable file names.

Source

Thrown at crates/codegen/xai-grok-shell/src/session/workflow/store.rs:295

        validate_run_id(run_id).ok()?;
        self.sources.lock().contains_key(run_id).then_some(())?;
        Some(self.run_dir(run_id)?.join("script.rhai"))
    }

    fn run_dir(&self, run_id: &str) -> Option<PathBuf> {
        self.session_dir
            .as_ref()
            .map(|dir| dir.join("workflows").join(run_id))
    }
}

pub(crate) fn validate_run_id(run_id: &str) -> io::Result<()> {
    if run_id.is_empty()
        || !run_id
            .bytes()
            .all(|b| b.is_ascii_alphanumeric() || b == b'_' || b == b'-')
    {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "invalid workflow run id",
        ));
    }
    Ok(())
}

pub(crate) fn script_revision_path(run_dir: &Path, revision: u32) -> PathBuf {
    run_dir.join("scripts").join(format!("{revision:04}.rhai"))
}

pub(crate) fn read_bounded_nofollow(path: &Path, limit: u64) -> io::Result<Vec<u8>> {
    let metadata = std::fs::symlink_metadata(path)?;
    if metadata.file_type().is_symlink() || !metadata.is_file() {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!(
                "workflow artifact is not a regular file: {}",

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Sanitize the run id to [A-Za-z0-9_-]+ before calling register/script_copy_path
  2. Reject empty ids at the workflow creation boundary
  3. Generate ids from a vetted source (uuid simple format) instead of user input

Example fix

// before
store.register(&user_provided_id, ...)?; // "2024/01/01" -> invalid workflow run id
// after
let id: String = user_provided_id.chars().filter(|c| c.is_ascii_alphanumeric() || *c=='_' || *c=='-').collect();
let id = if id.is_empty() { uuid::Uuid::now_v7().simple().to_string() } else { id };
store.register(&id, ...)?;
Defensive patterns

Strategy: validation

Validate before calling

fn valid_run_id(id: &str) -> bool {
    !id.is_empty()
        && id.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_' || b == b'-')
}
// call before: if !valid_run_id(&id) { reject }

Type guard

fn as_run_id(s: &str) -> Option<&str> {
    match s {
        s if !s.is_empty() && s.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_' || b == b'-') => Some(s),
        _ => None,
    }
}

Try / catch

if let Err(e) = store.validate_run_id(&id) {
    return Err(UserInputError::new("run id must match [A-Za-z0-9_-]+", e));
}
let manifest = store.register(&id, ...)?;

Prevention

When it happens

Trigger: register() or script_copy_path() called with an empty run id or one containing '/', '..', spaces, unicode, or other punctuation, e.g. a user-supplied or externally generated run identifier.

Common situations: Run ids derived from URLs, timestamps with separators like ':' or '/', user input passed through unvalidated, or empty ids when a workflow failed to allocate an id.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/230b5ed669bf0857. Report an issue: GitHub.