rustfs/rustfs · error · policy::Error

'Resource' and 'NotResource' cannot both be specified in the

Error message

'Resource' and 'NotResource' cannot both be specified in the same statement

What it means

Returned by Statement::is_valid (crates/policy/src/policy/statement.rs:343) when a statement lists both a non-empty Resource and a non-empty NotResource. Like Action/NotAction, the positive and negated resource selectors are mutually exclusive; a statement containing both is rejected at parse time.

Source

Thrown at crates/policy/src/policy.rs:58

#[derive(thiserror::Error, Debug)]
#[cfg_attr(test, derive(Eq, PartialEq))]
pub enum Error {
    #[error("invalid Version '{0}'")]
    InvalidVersion(String),

    #[error("invalid Effect '{0}'")]
    InvalidEffect(String),

    #[error("both 'Action' and 'NotAction' are empty")]
    NonAction,

    #[error("'Action' and 'NotAction' cannot both be specified in the same statement")]
    BothActionAndNotAction,

    #[error("'Resource' is empty")]
    NonResource,

    #[error("'Resource' and 'NotResource' cannot both be specified in the same statement")]
    BothResourceAndNotResource,

    #[error("invalid key name: '{0}'")]
    InvalidKeyName(String),

    #[error("invalid key: '{0}'")]
    InvalidKey(String),

    #[error("invalid action: '{0}'")]
    InvalidAction(String),

    #[error("'Action' contains mixed action families in the same statement")]
    MixedActionFamilies,

    #[error("invalid resource, type: '{0}', pattern: '{1}'")]
    InvalidResource(String, String),

    #[error("KMS resources require a statement whose actions are all KMS actions")]

View on GitHub (pinned to 35af688cd9)

Solutions

  1. Delete one of the two keys so each statement has exactly one resource selection mode
  2. Split into two statements if both scopes genuinely need different effects
  3. Automate a pre-flight check that flags statements containing both keys

Example fix

// before
{ "Effect": "Deny",
  "Action": "s3:*",
  "Resource": "arn:aws:s3:::secret/*",
  "NotResource": "arn:aws:s3:::public/*" }

// after
{ "Effect": "Deny",
  "Action": "s3:*",
  "Resource": "arn:aws:s3:::secret/*" }
Defensive patterns

Strategy: validation

Validate before calling

fn not_both_resource_modes(stmt: &serde_json::Value) -> bool {
    let has = |k: &str| stmt.get(k).map(|v| !v.is_null()).unwrap_or(false);
    !(has("Resource") && has("NotResource"))
}

Try / catch

match statement.is_valid() {
    Err(Error::PolicyError(IamError::BothResourceAndNotResource)) => { /* keep one mode */ }
    Ok(()) => { /* ok */ }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A policy statement JSON containing both "Resource" and "NotResource" keys with non-empty values in any policy upload path.

Common situations: Incremental policy editing where a NotResource was added to exclude a new bucket but the original Resource list was left in place; merging policies with a naive union of fields.

Related errors


AI-assisted analysis of rustfs/rustfs@35af688cd9 (2026-08-20). Data as JSON: /api/errors/46579440742231a7. Report an issue: GitHub.