{"record":{"id":"91e8d51fd28e4f05","repo":"commaai/openpilot","slug":"custom-series-returned-an-empty-result","errorCode":null,"errorMessage":"Custom series returned an empty result","messagePattern":"Custom series returned an empty result","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"openpilot/tools/jotpluggler/math_eval.py","lineNumber":131,"sourceCode":"  if globals_code.strip():\n    exec(globals_code, env, env)\n\n  with open(code_path, encoding=\"utf-8\") as f:\n    user_code = f.read()\n  result = _evaluate_user_code(user_code, env)\n\n  if isinstance(result, tuple) and len(result) == 2:\n    result_t, result_v = result\n  else:\n    if first_path is None:\n      raise ValueError(\"No reference series found. Set an input timeseries or return (times, values).\")\n    result_t = series_t[first_path]\n    result_v = result\n\n  result_t = np.asarray(result_t, dtype=np.float64).reshape(-1)\n  result_v = np.asarray(result_v, dtype=np.float64).reshape(-1)\n  if result_t.size == 0 or result_v.size == 0:\n    raise ValueError(\"Custom series returned an empty result\")\n  if result_t.shape != result_v.shape:\n    raise ValueError(f\"Time/value arrays must have the same shape, got {result_t.shape} and {result_v.shape}\")\n\n  _write_vector(out_t_path, result_t)\n  _write_vector(out_v_path, result_v)\n  return 0\n\n\nif __name__ == \"__main__\":\n  try:\n    raise SystemExit(main())\n  except Exception as err:\n    traceback.print_exc()\n    raise SystemExit(1) from err\n","sourceCodeStart":113,"sourceCodeEnd":146,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/tools/jotpluggler/math_eval.py#L113-L146","documentation":"math_eval converts the evaluated result's time and value arrays to float64 1-D arrays and requires both to be non-empty. An empty result means the user's code returned empty arrays (or sliced an input down to nothing), so there is no data to write to the output vector files, and it fails fast.","triggerScenarios":"User code returns [], np.array([]), or an empty tuple element; boolean masking that filtered out every sample (e.g. wrong comparison direction); result derived from an empty input series.","commonSituations":"A filter like src_v[src_v > 100] where no values exceed the threshold; time-window slice outside the data range returning zero rows; upstream input file empty.","solutions":["Debug the expression: print(len(result_v)) and intermediate masks in the code file to find where rows drop to zero","Fix the filter/threshold so it selects at least some samples, or guard: 'return src_v[mask] if mask.any() else src_v'","If an input series is unexpectedly empty, check the input vector files fed to the metric"],"exampleFix":"# before\nreturn src_v[src_v > 100.0]  # all values below 100 -> empty\n\n# after\nmask = src_v > 100.0\nif not mask.any():\n    raise ValueError(\"no samples above threshold - check units\")\nreturn src_v[mask]","handlingStrategy":"validation","validationCode":"out = np.asarray(result_v if isinstance(result, tuple) else result, dtype=np.float64).reshape(-1)\nif out.size == 0:\n    raise SystemExit('expression produced zero samples - check filters/thresholds and input data')","typeGuard":null,"tryCatchPattern":"try:\n    main()\nexcept ValueError as e:\n    if 'empty result' in str(e):\n        print('mask kept no samples; loosen filters or verify input vectors')\n        raise SystemExit(2)\n    raise","preventionTips":["Guard masks in metric code: 'if not mask.any(): raise ValueError(diagnostic)' with a specific message","Sanity-check input vector lengths before running the metric; empty inputs yield empty outputs"],"tags":["jotpluggler","math-eval","empty-data","validation","openpilot"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}