let header
    ?version ?sort_order ?(ref_seqs=[]) ?(read_groups=[])
    ?(programs=[]) ?(comments=[]) ?(others=[])
    ()
    =
  [
    (
      match version with
      | None -> None
      | Some x -> match parse_header_version x with
        | Error e -> Some e
        | Ok _ -> None
    );
    (
      if Option.is_some sort_order && (version = Nonethen
        Some (Error.create
                "sort order cannot be defined without version"
                (sort_order, version)
                <:sexp_of< sort_order option * string option >>
        )
      else
        None
    );
    (
      List.map ref_seqs ~f:(fun (x:ref_seq) -> x.name)
      |> List.find_a_dup
      |> Option.map ~f:(fun name ->
         Error.create "duplicate ref seq name" name sexp_of_string
      )
    );
  ]
  |> List.filter_map ~f:Fn.id
  |> function
     | [] -> Ok {
       version; sort_order; ref_seqs; read_groups;
       programs; comments; others;
     }
     | errs -> Error (Error.of_list errs)