{"record":{"id":"408cb2ed8d5d3ac8","repo":"lllyasviel/Fooocus","slug":"max-depth-of-recursive-function-tie-encoder-to-de","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"critical","filePath":"extras/BLIP/models/blip_pretrain.py","lineNumber":321,"sourceCode":"\n            all_encoder_weights = set([module_name + \"/\" + sub_name for sub_name in encoder_modules.keys()])\n            encoder_layer_pos = 0\n            for name, module in decoder_modules.items():\n                if name.isdigit():\n                    encoder_name = str(int(name) + encoder_layer_pos)\n                    decoder_name = name\n                    if not isinstance(decoder_modules[decoder_name], type(encoder_modules[encoder_name])) and len(\n                        encoder_modules\n                    ) != len(decoder_modules):\n                        # this can happen if the name corresponds to the position in a list module list of layers\n                        # in this case the decoder has added a cross-attention that the encoder does not have\n                        # thus skip this step and subtract one layer pos from encoder\n                        encoder_layer_pos -= 1\n                        continue\n                elif name not in encoder_modules:\n                    continue\n                elif depth > 500:\n                    raise ValueError(\n                        \"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.\"\n                    )\n                else:\n                    decoder_name = encoder_name = name\n                tie_encoder_to_decoder_recursively(\n                    decoder_modules[decoder_name],\n                    encoder_modules[encoder_name],\n                    module_name + \"/\" + name,\n                    uninitialized_encoder_weights,\n                    skip_key,\n                    depth=depth + 1,\n                )\n                all_encoder_weights.remove(module_name + \"/\" + encoder_name)\n\n            uninitialized_encoder_weights += list(all_encoder_weights)\n\n    # tie weights recursively\n    tie_encoder_to_decoder_recursively(decoder, encoder, base_model_prefix, uninitialized_encoder_weights, skip_key)  ","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/lllyasviel/Fooocus/blob/ae05379cc97bc4361ec8b4ec90193dab21be763f/extras/BLIP/models/blip_pretrain.py#L303-L339","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ntie_encoder_to_decoder(model.decoder, model.encoder)  # incompatible trees\n\n// after\ntie_encoder_to_decoder(model.decoder, model.encoder, skip_key='bert')","handlingStrategy":"validation","validationCode":"def can_tie_safely(encoder, decoder, skip_key=None):\n    enc_names = [n for n, _ in encoder.named_modules() if skip_key not in n]\n    dec_names = [n for n, _ in decoder.named_modules() if skip_key not in n]\n    return set(enc_names) & set(dec_names) != set()  # rough compatibility probe","typeGuard":null,"tryCatchPattern":"try:\n    tie_encoder_to_decoder(decoder, encoder, skip_key='bert')\nexcept ValueError as e:\n    if 'Max depth' in str(e):\n        raise RuntimeError('encoder/decoder module trees incompatible; check architectures') from e\n    raise","preventionTips":["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"],"tags":["blip","pytorch","recursion","weight-tying","model-config"],"backgroundTag":null,"analyzedSha":"ae05379cc97bc4361ec8b4ec90193dab21be763f","analyzedAt":"2026-08-15T04:23:59.533Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}