xai-org/x-algorithm · error · ValueError
enable_candidate_tower_linear_proj and feature_prep_enabled
Error message
enable_candidate_tower_linear_proj and feature_prep_enabled (candidate project-then-sum) are mutually exclusive; enable at most one (or neither for mean-pool on the candidate tower).
What it means
The two-tower xrecsys config validator rejects any ModelParams that enables both enable_candidate_tower_linear_proj and feature_prep_enabled. Both flags select a (mutually exclusive) reduction strategy for the candidate tower embeddings (linear projection vs project-then-sum feature prep), so enabling both makes the intended architecture ambiguous. The check deliberately runs before the emb_size % 128 assertion so misconfiguration fails fast at config-parse time rather than mid-training.
Source
Thrown at phoenix/xrex/configs/xrecsys_two_tower.py:517
use_user_features = _has_user_features_token(mparams)
dataset = _make_dataset(mparams, dataset_type, hash_table, config_name)
evals = []
for _build_evals in config_registry.RETRIEVAL_EVAL_BUILDERS:
evals += _build_evals(mparams, dataset, _has_user_features_token)
raw_checkpoint_datasets = mparams.get("checkpoint_dataset_names", None)
if isinstance(raw_checkpoint_datasets, str):
checkpoint_dataset_names = [
s.strip() for s in raw_checkpoint_datasets.split(",") if s.strip()
]
else:
checkpoint_dataset_names = raw_checkpoint_datasets
if mparams.get("enable_candidate_tower_linear_proj") and mparams.get(
"feature_prep_enabled", False
):
raise ValueError(
"enable_candidate_tower_linear_proj and feature_prep_enabled "
"(candidate project-then-sum) are mutually exclusive; enable at most one "
"(or neither for mean-pool on the candidate tower)."
)
assert mparams["emb_size"] % 128 == 0
assert mparams["emb_table_width"] % 128 == 0
hl = mparams["history_seq_len"]
use_user_embedding = mparams.get("use_user_embedding", True)
scale_config = _default_recsys_scaling()
num_user_prefix_tokens = _num_user_prefix_tokens(mparams, use_user_embedding, scale_config)
total_seq = num_user_prefix_tokens + hl
use_seqpack = mparams.get("use_seqpack", False)
if num_user_prefix_tokens > 1:
assert (total_seq & (total_seq - 1)) == 0, (
f"total sequence length ({total_seq} = {num_user_prefix_tokens} + {hl}) must be a power of 2"
)View on GitHub (pinned to 24c60942c5)
Solutions
- If you want a projection on the candidate tower, keep enable_candidate_tower_linear_proj=True and set feature_prep_enabled=False.
- If you want project-then-sum feature prep, set feature_prep_enabled=True and remove/False enable_candidate_tower_linear_proj.
- If you want neither (mean-pooling on the candidate tower), set both flags to False.
- Audit your YAML/CLI override chain to find where feature_prep_enabled gets enabled globally and scope it correctly.
Example fix
# before
mparams = dict(
enable_candidate_tower_linear_proj=True,
feature_prep_enabled=True,
)
# after (project-then-sum prep on candidate tower)
mparams = dict(
enable_candidate_tower_linear_proj=False,
feature_prep_enabled=True,
) Defensive patterns
Strategy: validation
Validate before calling
def validate_two_tower_mparams(mparams):
if mparams.get("enable_candidate_tower_linear_proj") and mparams.get(
"feature_prep_enabled", False
):
raise ValueError(
"pick one candidate-tower reduction: "
"enable_candidate_tower_linear_proj OR feature_prep_enabled (or neither)"
)
validate_two_tower_mparams(mparams) # before building the trainer Type guard
def has_valid_candidate_tower_flags(m) -> bool:
return not (m.get("enable_candidate_tower_linear_proj") and m.get("feature_prep_enabled", False)) Prevention
- Add a unit test asserting the config combo you ship does not set both flags.
- Document the three valid modes (linear proj / project-then-sum / mean-pool) next to the flags in the config template.
When it happens
Trigger: Setting both mparams['enable_candidate_tower_linear_proj']=True and mparams['feature_prep_enabled']=True in the two-tower config (or via CLI overrides / YAML merge that turns on feature prep globally while the model flags linear proj).
Common situations: Copy-pasting a candidate-tower config that uses linear projection into a pipeline config where feature_prep_enabled is already on; flipping feature_prep_enabled for the query tower and forgetting it also affects the candidate tower; defaults changing between config versions so an old flag now conflicts.
Related errors
- Invalid argument {arg!r}, not a key=value replacement and no
- Expected bool [True, true, False, false], got {val!r}
- Got {val} for union type {ty}
- Tuple {ty} has different number of arguments from given valu
- Literal {ty} does not allow for {val!r}
AI-assisted analysis of xai-org/x-algorithm@24c60942c5 (2026-08-28).
Data as JSON: /api/errors/f107127063b199d3.
Report an issue: GitHub.