huggingface/candle · error

bool_masked_pos set without mask_token

Error message

bool_masked_pos set without mask_token

What it means

ViT forward supports masking patches via bool_masked_pos, but replacing masked positions requires the model to have mask_token weights. If a mask tensor is supplied while self.mask_token is None (the checkpoint/config had no mask token), forward bails rather than silently ignoring the mask.

Source

Thrown at candle-transformers/src/models/vit.rs:159

        &self,
        _embeddings: &Tensor,
        _height: usize,
        _width: usize,
    ) -> Result<Tensor> {
        todo!()
    }

    pub fn forward(
        &self,
        pixel_values: &Tensor,
        bool_masked_pos: Option<&Tensor>,
        interpolate_pos_encoding: bool,
    ) -> Result<Tensor> {
        let (b_size, _num_channels, height, width) = pixel_values.dims4()?;
        let embeddings = self.patch_embeddings.forward(pixel_values)?;
        let embeddings = match (bool_masked_pos, &self.mask_token) {
            (None, _) => embeddings,
            (Some(_), None) => candle::bail!("bool_masked_pos set without mask_token"),
            (Some(bool_masked_pos), Some(mask_tokens)) => {
                let seq_len = embeddings.dim(1)?;
                let mask_tokens = mask_tokens.broadcast_as((b_size, seq_len, self.hidden_size))?;
                let mask = bool_masked_pos
                    .unsqueeze(D::Minus1)?
                    .to_dtype(mask_tokens.dtype())?;
                ((mask_tokens * &mask)? - (embeddings * (mask - 1.)?)?)?
            }
        };
        let cls_tokens = self.cls_token.broadcast_as((b_size, 1, self.hidden_size))?;
        let embeddings = Tensor::cat(&[&cls_tokens, &embeddings], 1)?;
        if interpolate_pos_encoding {
            let pos = self.interpolate_pos_encoding(&embeddings, height, width)?;
            embeddings.broadcast_add(&pos)
        } else {
            embeddings.broadcast_add(&self.position_embeddings)
        }
    }

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Pass None for bool_masked_pos if you do not need masked patch modeling
  2. Load a checkpoint/config that includes mask_token weights (e.g. an MAE-style ViT)
  3. Set use_mask_token/mask-token in the config so the mask_token parameter is created before load

Example fix

// before
let emb = model.forward(&pixels, Some(&mask_pos), false)?;
// after (plain ViT without mask_token)
let emb = model.forward(&pixels, None, false)?;
Defensive patterns

Strategy: type-guard

Validate before calling

if bool_masked_pos.is_some() && model.mask_token.is_none() {
    return Err(anyhow::anyhow!("model has no mask_token; pass None for bool_masked_pos"));
}

Type guard

fn masking_supported(model: &ViTModel) -> bool {
    model.mask_token.is_some()
}

Try / catch

match model.forward(&pixels, mask_pos, false) {
    Err(e) if e.to_string().contains("bool_masked_pos set without mask_token") => {
        model.forward(&pixels, None, false)?
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling vit.forward(pixel_values, Some(bool_masked_pos), interpolate_pos_encoding) on a ViTModel/VisionTransformer built from a config/checkpoint without a mask_token.

Common situations: Reusing MAE-style masking code with a plain supervised ViT checkpoint that never trained a mask token; copying forward calls from MAE examples; a config field for mask token left unset.

Related errors


AI-assisted analysis of huggingface/candle@d5fee525bf (2026-09-02). Data as JSON: /api/errors/adc2560251360135. Report an issue: GitHub.