{"record":{"id":"3e9101e4d8d6c2e6","repo":"jax-ml/jax","slug":"custom-vjp-bwd-rule-self-bwd-was-registered-with-3e9101","errorCode":null,"errorMessage":"Custom VJP bwd rule {self.bwd} was registered with defvjp_with_logs, and so the second element of the pair it returns must be None or a dict of backward-pass log entries, but got {type(logs).__name__}.","messagePattern":"Custom VJP bwd rule (.+?) was registered with defvjp_with_logs, and so the second element of the pair it returns must be None or a dict of backward-pass log entries, but got (.+?)\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"jax/_src/hijax.py","lineNumber":789,"sourceCode":"  def vjp_bwd_retval(self, res, out_ct):\n    static_args = tuple(x.val for x in self.in_avals if isinstance(x, Static))\n    in_avals_ = tuple(x for x in self.in_avals if not isinstance(x, Static))\n    leaf = lambda x: isinstance(x, ad_util.Zero)\n    if self.symbolic_zeros:\n      out_ct = tree_map(ad_util.replace_internal_symbolic_zeros, out_ct, is_leaf=leaf)\n    else:\n      out_ct = tree_map(ad_util.instantiate, out_ct, is_leaf=leaf)\n    in_cts = self.bwd(*static_args, res, out_ct)\n    logs = None\n    if self.with_logs:\n      if not (isinstance(in_cts, (list, tuple)) and len(in_cts) == 2):\n        raise TypeError(\n            f\"Custom VJP bwd rule {self.bwd} was registered with \"\n            \"defvjp_with_logs and so must produce a pair (in_cts, logs), \"\n            f\"but got {in_cts}.\")\n      in_cts, logs = in_cts\n      if logs is not None and type(logs) is not dict:\n        raise TypeError(\n            f\"Custom VJP bwd rule {self.bwd} was registered with \"\n            \"defvjp_with_logs, and so the second element of the pair it \"\n            \"returns must be None or a dict of backward-pass log entries, \"\n            f\"but got {type(logs).__name__}.\")\n    if isinstance(in_cts, list):\n      in_cts = tuple(in_cts)\n    if not isinstance(in_cts, tuple):\n      raise TypeError(f\"Custom VJP bwd rule {self.bwd} must produce a tuple \"\n                      f\"but got {type(in_cts)}.\")\n    in_cts = (None, None, *in_cts)  # zero cts for the consts and fwd_consts args\n    if len(in_cts) != len(self.in_tree.children()) - len(self.static_argnums):\n      raise ValueError(f\"Custom VJP bwd rule {self.bwd} must produce a tuple \"\n                       \"of length equal to the primal args tuple, but got \"\n                       f\"length {len(in_cts)}\")\n    in_cts = broadcast_prefix(in_cts, in_avals_, is_leaf=lambda x: x is None)\n    in_cts = tree_unflatten(self.in_tree, map(_replace_none, self.in_avals_flat, in_cts))\n    tree_map_with_path(partial(_vjp_bwd_aval_mismatch_err, self.traced._fun_sourceinfo),\n                               self.in_avals[2:], in_cts[2:])","sourceCodeStart":771,"sourceCodeEnd":807,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/hijax.py#L771-L807","documentation":"For a defvjp_with_logs-registered backward rule, the second element of the returned pair must be None or a dict of log entries; another type fails this TypeError after the pair was unpacked.","triggerScenarios":"bwd returns a pair whose second element is a list, string, or array rather than None/dict.","commonSituations":"Returning a list of log tensors or a scalar metric instead of a named dict of logs.","solutions":["Return None or a plain dict, e.g. `(cts, {'grad_norm': g})`","Convert list-based logs to a dict with keys"],"exampleFix":"# before\nreturn cts, [g1, g2]\n# after\nreturn cts, {'g1': g1, 'g2': g2}","handlingStrategy":"type-guard","validationCode":"cts, logs = bwd(*static_args, res, out_ct)\nassert logs is None or type(logs) is dict","typeGuard":"def logs_valid(logs) -> bool:\n    return logs is None or type(logs) is dict","tryCatchPattern":"try:\n    jax.grad(f)(x)\nexcept TypeError as e:\n    if 'dict of backward-pass log entries' in str(e):\n        raise RuntimeError('second element must be None or dict') from e\n    raise","preventionTips":["Use dicts with named keys for logs","Never return lists/arrays as the logs element"],"tags":["jax","custom-vjp","logging","type-validation"],"backgroundTag":"custom-vjp-return-shape","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}