lllyasviel/Fooocus · critical · ValueError
Max depth of recursive function `tie_encoder_to_decoder` rea
Error message
Max depth of recursive function `tie_encoder_to_decoder` reached. It seems that there is a circular dependency between two or more `nn.Modules` of your model.
What it means
tie_encoder_to_decoder_recursively walks the encoder and decoder module trees in lockstep to tie (share) weights; if the recursion depth exceeds 500 it concludes the module graph contains a cycle (a module that contains itself as a child), which would recurse forever. In practice this is raised when the structures of the two modules diverge so badly that name-based matching descends into mismatched subtrees indefinitely.
Source
Thrown at extras/BLIP/models/blip_pretrain.py:321
all_encoder_weights = set([module_name + "/" + sub_name for sub_name in encoder_modules.keys()])
encoder_layer_pos = 0
for name, module in decoder_modules.items():
if name.isdigit():
encoder_name = str(int(name) + encoder_layer_pos)
decoder_name = name
if not isinstance(decoder_modules[decoder_name], type(encoder_modules[encoder_name])) and len(
encoder_modules
) != len(decoder_modules):
# this can happen if the name corresponds to the position in a list module list of layers
# in this case the decoder has added a cross-attention that the encoder does not have
# thus skip this step and subtract one layer pos from encoder
encoder_layer_pos -= 1
continue
elif name not in encoder_modules:
continue
elif depth > 500:
raise ValueError(
"Max depth of recursive function `tie_encoder_to_decoder` reached. It seems that there is a circular dependency between two or more `nn.Modules` of your model."
)
else:
decoder_name = encoder_name = name
tie_encoder_to_decoder_recursively(
decoder_modules[decoder_name],
encoder_modules[encoder_name],
module_name + "/" + name,
uninitialized_encoder_weights,
skip_key,
depth=depth + 1,
)
all_encoder_weights.remove(module_name + "/" + encoder_name)
uninitialized_encoder_weights += list(all_encoder_weights)
# tie weights recursively
tie_encoder_to_decoder_recursively(decoder, encoder, base_model_prefix, uninitialized_encoder_weights, skip_key) View on GitHub (pinned to ae05379cc9)
Solutions
- Check that encoder and decoder are the intended objects — you must not pass the same module (or a module containing the other) for both
- Use the skip_key argument (e.g. skip_key='bert') to stop recursion at mismatched shared submodules, as BLIP's pretrain code does
- Verify config.json / model construction matches the checkpoint architecture (num layers, layer names) so lockstep traversal stays aligned
- Inspect model.named_modules() for duplicated/self-referential entries introduced by custom code
Example fix
// before tie_encoder_to_decoder(model.decoder, model.encoder) # incompatible trees // after tie_encoder_to_decoder(model.decoder, model.encoder, skip_key='bert')
Defensive patterns
Strategy: validation
Validate before calling
def can_tie_safely(encoder, decoder, skip_key=None):
enc_names = [n for n, _ in encoder.named_modules() if skip_key not in n]
dec_names = [n for n, _ in decoder.named_modules() if skip_key not in n]
return set(enc_names) & set(dec_names) != set() # rough compatibility probe Try / catch
try:
tie_encoder_to_decoder(decoder, encoder, skip_key='bert')
except ValueError as e:
if 'Max depth' in str(e):
raise RuntimeError('encoder/decoder module trees incompatible; check architectures') from e
raise Prevention
- Always pass skip_key when tying BLIP encoder to a text decoder
- Never register a module as a child of itself
- Unit-test weight tying after every architecture change
When it happens
Trigger: Calling tie_encoder_to_decoder(decoder, encoder) where encoder and decoder are architecturally incompatible (e.g. tying a BertModel encoder to a decoder whose layer list lengths/names mismatch), or where a module was registered as its own child (circular nn.Module references), causing depth to grow past 500.
Common situations: Loading a BLIP pretrained checkpoint into a model config with different num_hidden_layers or renamed submodules; passing the decoder itself (or a wrapper containing it) as the encoder argument; custom modifications that add a module attribute pointing back to a parent.
Related errors
- Wrong activation value in EqualLinear: {activation}Supported
- checkpoint url or path is invalid
- checkpoint url or path is invalid
- The hidden size (%d) is not a multiple of the number of atte
- Wrong shape for input_ids (shape {}) or attention_mask (shap
AI-assisted analysis of lllyasviel/Fooocus@ae05379cc9 (2026-08-15).
Data as JSON: /api/errors/408cb2ed8d5d3ac8.
Report an issue: GitHub.