{"record":{"id":"fc84ba66a07eb8c8","repo":"commaai/openpilot","slug":"missing-output-name","errorCode":null,"errorMessage":"Missing output {name}","messagePattern":"Missing output (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"openpilot/selfdrive/modeld/parse_model_outputs.py","lineNumber":27,"sourceCode":"  return 1. / (1. + safe_exp(-x))\n\ndef softmax(x, axis=-1):\n  x -= np.max(x, axis=axis, keepdims=True)\n  if x.dtype == np.float32 or x.dtype == np.float64:\n    safe_exp(x, out=x)\n  else:\n    x = safe_exp(x)\n  x /= np.sum(x, axis=axis, keepdims=True)\n  return x\n\nclass Parser:\n  def __init__(self, ignore_missing=False):\n    self.ignore_missing = ignore_missing\n\n  def check_missing(self, outs, name):\n    missing = name not in outs\n    if missing and not self.ignore_missing:\n      raise ValueError(f\"Missing output {name}\")\n    return missing\n\n  def parse_categorical_crossentropy(self, name, outs, out_shape=None):\n    if self.check_missing(outs, name):\n      return\n    raw = outs[name]\n    if out_shape is not None:\n      raw = raw.reshape((raw.shape[0],) + out_shape)\n    outs[name] = softmax(raw, axis=-1)\n\n  def parse_binary_crossentropy(self, name, outs):\n    if self.check_missing(outs, name):\n      return\n    raw = outs[name]\n    outs[name] = sigmoid(raw)\n\n  def parse_mdn(self, name, outs, in_N=0, out_N=1, out_shape=()):\n    if self.check_missing(outs, name):","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/selfdrive/modeld/parse_model_outputs.py#L9-L45","documentation":"Parser.check_missing raises ValueError when a requested model output tensor name is absent from the outs dict, unless the Parser was constructed with ignore_missing=True. It guards against parsing a model whose output signature does not match what the parser expects.","triggerScenarios":"Running parse_categorical_crossentropy/parse_binary_crossentropy-style parsing (parse_model_outputs) on a model bundle whose ONNX/TFLite outputs were renamed or pruned, or mixing an old downloaded model with new parser code (or vice versa).","commonSituations":"Stale model weights in /data/models after an openpilot update changed output names, a custom-trained model with different head names, or an experiment model missing a head.","solutions":["Redownload/refresh the model bundle so outputs match the parser version","Print available output names (list(outs.keys())) and reconcile with the names the parser requests","If the output is genuinely optional for your use, construct Parser(ignore_missing=True) so missing outputs return None instead of raising"],"exampleFix":"// before\nparser = Parser()\nparser.parse_categorical_crossentropy('desire', outs)\n\n// after\nparser = Parser(ignore_missing=True)\nparser.parse_categorical_crossentropy('desire', outs)","handlingStrategy":"validation","validationCode":"required = ['desire', 'meta', 'pose']\nmissing = [n for n in required if n not in outs]\nif missing and not parser.ignore_missing:\n    raise ValueError(f'model outputs missing: {missing}')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep model bundles and parser code from the same openpilot version","After model updates, diff output tensor names against parser expectations","Use Parser(ignore_missing=True) for optional heads only, never to mask stale models in production"],"tags":["ml","model","parsing","version-mismatch"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}