BloopAI/vibe-kanban · critical

Pending approvals path should be valid

Error message

Pending approvals path should be valid

What it means

This panic comes from an `.expect()` on the conversion of the string constant "/pending" into a `json_patch` JSON Pointer type (`try_into()` on `PENDING_PATH`). The `json_patch` crate's path type only parses strings that are valid RFC 6901 JSON Pointers (must start with '/', escape ~ and / correctly). It throws when the string fails that parse, which for a hardcoded constant means the conversion is effectively infallible and the expect is a compile-time-invariant assertion.

Source

Thrown at crates/services/src/services/events/patches.rs:162

    fn pending_path(approval_id: &str) -> String {
        format!("{}/{}", PENDING_PATH, escape_pointer_segment(approval_id))
    }

    pub fn snapshot(pending: &[crate::services::approvals::ApprovalInfo]) -> Patch {
        let pending: serde_json::Map<String, serde_json::Value> = pending
            .iter()
            .map(|info| {
                (
                    info.approval_id.clone(),
                    serde_json::to_value(info).unwrap_or(serde_json::Value::Null),
                )
            })
            .collect();

        Patch(vec![PatchOperation::Replace(ReplaceOperation {
            path: PENDING_PATH
                .try_into()
                .expect("Pending approvals path should be valid"),
            value: serde_json::Value::Object(pending),
        })])
    }

    pub fn created(info: &crate::services::approvals::ApprovalInfo) -> Patch {
        let value = serde_json::to_value(info).unwrap_or(serde_json::Value::Null);
        Patch(vec![PatchOperation::Replace(ReplaceOperation {
            path: pending_path(&info.approval_id)
                .try_into()
                .expect("Approval path should be valid"),
            value,
        })])
    }

    pub fn resolved(approval_id: &str) -> Patch {
        Patch(vec![PatchOperation::Remove(RemoveOperation {
            path: pending_path(approval_id)
                .try_into()

View on GitHub (pinned to 4deb7eca8f)

Solutions

  1. Verify PENDING_PATH is a valid JSON Pointer: starts with '/' and any '~' or '/' inside segments are escaped as ~0/~1 (escape_pointer_segment already does this for dynamic parts).
  2. If you changed the constant, restore the leading slash, e.g. "/pending".
  3. Replace the expect with a parse at construction time (e.g. JsonPointer::from_static or a once-built static) so an invalid constant fails at compile/startup rather than per event.
  4. Pin or update json_patch to a compatible version if the parse rules changed after an upgrade.

Example fix

// before
const PENDING_PATH: &str = "pending";
path: PENDING_PATH.try_into().expect("Pending approvals path should be valid"),
// after
const PENDING_PATH: &str = "/pending"; // valid JSON Pointer
path: PENDING_PATH.try_into().expect("Pending approvals path should be valid"),
Defensive patterns

Strategy: validation

Validate before calling

// Compile-time/startup guard for the constant
fn assert_valid_pointer(p: &str) {
    assert!(p.starts_with('/'), "invalid JSON Pointer: {p}");
    json_patch::Pointer::try_from(p).expect("PENDING_PATH must be a valid JSON Pointer");
}
const PENDING_PATH: &str = "/pending";
const _: () = assert!("/pending".starts_with('/'));

Type guard

fn is_valid_pointer(s: &str) -> bool {
    s.starts_with('/') && json_patch::Pointer::try_from(s).is_ok()
}

Try / catch

// Rust cannot catch panics safely in normal flow; prefer non-panicking parse:
match PENDING_PATH.try_into() {
    Ok(path) => /* build patch */,
    Err(e) => log::error!("invalid pending path: {e}"),
}

Prevention

When it happens

Trigger: Only when `PENDING_PATH` ("/pending") somehow fails `json_patch::path::JsonPointer::try_from(&str)` parsing — i.e. if the constant were edited to not start with '/' or to contain invalid escapes. Not triggerable by user input since the path never includes dynamic data.

Common situations: A developer edits PENDING_PATH and introduces an invalid JSON Pointer (missing leading '/', empty string, or unescaped '~'/'/' if it were dynamic). Upgrading the json_patch crate to a version with stricter pointer validation could also surface this.

Related errors


AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29). Data as JSON: /api/errors/0a9d18391a58c939. Report an issue: GitHub.