invoke-ai/InvokeAI · error · ValueError
`class_embed_type`: 'projection' requires `projection_class_
Error message
`class_embed_type`: 'projection' requires `projection_class_embeddings_input_dim` be set
What it means
When `class_embed_type='projection'`, the class-label embedding is a linear projection whose input size must be known, so `projection_class_embeddings_input_dim` is mandatory. The constructor raises this ValueError when the projection type is selected but the input dimension is missing, because TimestepEmbedding cannot be sized without it. Related: when this projection type is used, `addition_embed_type` must typically also be None, and adding_time_dims derive from this value.
Source
Thrown at invokeai/backend/util/hotfixes.py:238
)
elif encoder_hid_dim_type is not None:
raise ValueError(
f"encoder_hid_dim_type: {encoder_hid_dim_type} must be None, 'text_proj' or 'text_image_proj'."
)
else:
self.encoder_hid_proj = None
# class embedding
if class_embed_type is None and num_class_embeds is not None:
self.class_embedding = nn.Embedding(num_class_embeds, time_embed_dim)
elif class_embed_type == "timestep":
self.class_embedding = TimestepEmbedding(timestep_input_dim, time_embed_dim)
elif class_embed_type == "identity":
self.class_embedding = nn.Identity(time_embed_dim, time_embed_dim)
elif class_embed_type == "projection":
if projection_class_embeddings_input_dim is None:
raise ValueError(
"`class_embed_type`: 'projection' requires `projection_class_embeddings_input_dim` be set"
)
# The projection `class_embed_type` is the same as the timestep `class_embed_type` except
# 1. the `class_labels` inputs are not first converted to sinusoidal embeddings
# 2. it projects from an arbitrary input dimension.
#
# Note that `TimestepEmbedding` is quite general, being mainly linear layers and activations.
# When used for embedding actual timesteps, the timesteps are first converted to sinusoidal embeddings.
# As a result, `TimestepEmbedding` can be passed arbitrary vectors.
self.class_embedding = TimestepEmbedding(projection_class_embeddings_input_dim, time_embed_dim)
else:
self.class_embedding = None
if addition_embed_type == "text":
if encoder_hid_dim is not None:
text_time_embedding_from_dim = encoder_hid_dim
else:
text_time_embedding_from_dim = cross_attention_dimView on GitHub (pinned to 0b6a024f2f)
Solutions
- Set `projection_class_embeddings_input_dim` to the summed size of all conditioning embeddings (e.g. SDXL: 2816 = 4*281 timesteps + 768 text + 1280+... per model card).
- If you don't need projection class embedding, change `class_embed_type` to None, 'timestep', or 'identity'.
- Load with the original, complete config.json via from_pretrained instead of reconstructing kwargs manually.
- Diff your constructor kwargs against the upstream reference config for the checkpoint you are loading.
Example fix
// before
model = ControlNetModel2_5(
class_embed_type="projection",
addition_embed_type="text_time",
)
// after
model = ControlNetModel2_5(
class_embed_type="projection",
addition_embed_type="text_time",
projection_class_embeddings_input_dim=2816,
) Defensive patterns
Strategy: validation
Validate before calling
if model_config.get("class_embed_type") == "projection" and model_config.get("projection_class_embeddings_input_dim") is None:
raise ValueError("class_embed_type='projection' needs projection_class_embeddings_input_dim") Type guard
def projection_config_complete(cfg: dict) -> bool:
if cfg.get("class_embed_type") != "projection":
return True
return isinstance(cfg.get("projection_class_embeddings_input_dim"), int) Try / catch
try:
model = ControlNetModel2_5(**cfg)
except ValueError as e:
if "projection_class_embeddings_input_dim" in str(e):
cfg["projection_class_embeddings_input_dim"] = 2816 # SDXL default total cond dim
model = ControlNetModel2_5(**cfg)
else:
raise Prevention
- Copy the full key group (class_embed_type, projection_class_embeddings_input_dim, addition_embed_type, addition_time_embed_dim) as a unit from the reference config.
- Compute the projection dim as the sum of all conditioning embedding widths for your base model.
- Use from_pretrained with the shipped config.json instead of reconstructing model kwargs.
- Sanity-check configs against upstream examples for SDXL-family checkpoints.
When it happens
Trigger: Constructing the model with `class_embed_type="projection"` while `projection_class_embeddings_input_dim` is None/omitted — e.g. a partially copied SDXL-style config where the projection keys were dropped, or a config.json that sets class_embed_type without the accompanying dimension key.
Common situations: Adapting an SDXL/SSD-1B config onto a ControlNet/UNet class; truncating a config dict when copying only some keys; checkpoint configs authored for models that defaulted projection_class_embeddings_input_dim at a higher level (pipeline/scheduler config) instead of the model config.
Related errors
- `encoder_hid_dim` has to be defined when `encoder_hid_dim_ty
- encoder_hid_dim_type: {encoder_hid_dim_type} must be None, '
- addition_embed_type: {addition_embed_type} must be None, 'te
- User not found or inactive
- Missing authentication credentials
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/788a195b6f6f1900.
Report an issue: GitHub.