diem/diem · error · anyhow::Error

Invalid module access. Did not expect type arguments

Error message

Invalid module access. Did not expect type arguments

What it means

parse_qualified_module_access parses a string like '0x1::coin::Coin' into (ModuleId, Identifier) via parse_type_tag. A struct TypeTag with generic type parameters (e.g. '0x2::coin::Coin<0x1::sui::SUI>') is rejected because module access in test directives must reference a plain module member without generics. Non-struct type tags are rejected with the sibling 'Invalid module access' error.

Source

Thrown at language/testing-infra/transactional-test-runner/src/tasks.rs:329

        }
    }
}

#[derive(Debug, StructOpt)]
pub struct EmptyCommand {}

fn parse_account_address(s: &str) -> Result<AccountAddress> {
    let n = move_lang::shared::parse_u128(s)
        .map_err(|e| anyhow!("Failed to parse address. Got error: {}", e))?;
    Ok(AccountAddress::new(n.to_be_bytes()))
}

fn parse_qualified_module_access(s: &str) -> Result<(ModuleId, Identifier)> {
    match move_core_types::parser::parse_type_tag(s)? {
        TypeTag::Struct(s) => {
            let id = ModuleId::new(s.address, s.module);
            if !s.type_params.is_empty() {
                bail!("Invalid module access. Did not expect type arguments")
            }
            Ok((id, s.name))
        }
        _ => bail!("Invalid module access"),
    }
}

fn parse_qualified_module_access_with_type_args(
    s: &str,
) -> Result<(ModuleId, Identifier, Vec<TypeTag>)> {
    match move_core_types::parser::parse_type_tag(s)? {
        TypeTag::Struct(s) => {
            let id = ModuleId::new(s.address, s.module);
            Ok((id, s.name, s.type_params))
        }
        _ => bail!("Invalid module access"),
    }
}

View on GitHub (pinned to fc4714a8ea)

Solutions

  1. Remove the <...> type arguments and pass only the module/member path, e.g. 0x2::coin::Coin
  2. If generics are needed, check whether the directive or harness supports type args elsewhere; this parser does not
  3. Ensure the string parses as a struct type tag: address::module::name form

Example fix

// before
//# resource-query 0x2::coin::Coin<0x1::sui::SUI>
// after
//# resource-query 0x2::coin::Coin
Defensive patterns

Strategy: validation

Validate before calling

fn has_no_type_args(s: &str) -> bool {
    let t = move_core_types::parser::parse_type_tag(s).ok();
    matches!(t, Some(TypeTag::Struct(st)) if st.type_params.is_empty())
}

Type guard

fn plain_module_access(s: &str) -> Option<(ModuleId, Identifier)> {
    match move_core_types::parser::parse_type_tag(s).ok()? {
        TypeTag::Struct(st) if st.type_params.is_empty() =>
            Some((ModuleId::new(st.address, st.module), st.name)),
        _ => None,
    }
}

Try / catch

match parse_qualified_module_access(arg) {
    Err(e) if e.to_string().contains("Did not expect type arguments") => {
        bail!("strip <...> generics from module path: {}", arg)
    }
    other => other,
}

Prevention

When it happens

Trigger: Passing a qualified name with type arguments such as '0x2::coin::Coin<u64>' to a directive that expects parse_qualified_module_access; also any non-struct type tag (primitives, vectors) hits the generic 'Invalid module access' branch instead.

Common situations: Copy-pasting a generic struct type (with <...>) where a module/function path is required, e.g. in resource-query or publish-related test directives.

Related errors


AI-assisted analysis of diem/diem@fc4714a8ea (2026-09-04). Data as JSON: /api/errors/30a6d947f66d0764. Report an issue: GitHub.