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
- Sanitize the run id to [A-Za-z0-9_-]+ before calling register/script_copy_path
- Reject empty ids at the workflow creation boundary
- 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
- Validate run ids at the API boundary before any store call
- Generate ids from uuid simple format or base64url-free schemes
- Never build run ids from raw URLs, timestamps with ':'/'/', or user free-text
- Add a unit test that rejects ids containing '..', '/', spaces, and unicode
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
- invalid worktree id from dest: {worktree_id}
- invalid worktree id {:?}
- invalid {GROK_CHAT_LOCAL_WORKSPACE_MODE_ENV}={other:?}; expe
- Error: --session-id must be a valid UUID (got '{session_id}'
- {CHAT_MODE_FORK_CONFLICT}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/230b5ed669bf0857.
Report an issue: GitHub.