anchor.diff:                      end,
       Ports = proplists:get_value(<<"ports">>, Props),
   
  -    %% this is ensured by `extract_node_props' function
  +    %% this is ensured by `maybe_extract_important_buckets_props' function
       true = (Hostname =/= undefined),
  -    true = (CouchApiBase0 =/= undefined),
       true = (Ports =/= undefined),
   
  -    {Host, _Port} = host_and_port(Hostname),
  -    CouchApiBase = add_credentials(CouchApiBase0, Creds),
  -
  -    expect_nested_number(
  -      <<"direct">>, Ports, <<"node ports object">>,
  -      fun (DirectPort) ->
  -              McdUri = iolist_to_binary([Host, $:, integer_to_list(DirectPort)]),
  -              NewDict = dict:store(McdUri, CouchApiBase, Dict),
  -
  -              do_with_mcd_to_couch_uri_dict(Rest, NewDict, Creds, Cert, K)
  -      end).
  +    case CouchApiBase0 of
  +        undefined ->
  +            ?log_debug("Skipping node without either couchApiBase or couchApiBaseHTTPS (~s)", [Hostname]),
  +            do_with_mcd_to_couch_uri_dict(Rest, Dict, Creds, Cert, K);
  +        _ ->
  +            {Host, _Port} = host_and_port(Hostname),
  +            CouchApiBase = add_credentials(CouchApiBase0, Creds),
  +
  +            expect_nested_number(
  +              <<"direct">>, Ports, <<"node ports object">>,
  +              fun (DirectPort) ->
  +                      McdUri = iolist_to_binary([Host, $:, integer_to_list(DirectPort)]),
  +                      NewDict = dict:store(McdUri, CouchApiBase, Dict),
  +
  +                      do_with_mcd_to_couch_uri_dict(Rest, NewDict, Creds, Cert, K)
  +              end)
  +    end.
   
   add_credentials(URLBinary, {Username, Password}) ->
       URL = binary_to_list(URLBinary),
  
positive.code:     expect_nested_array(
        <<"nodes">>, Object, Context,
        fun (NodeList) ->
                Nodes =
                    lists:flatmap(
                      fun (Node) ->
                              extract_node_props(Props, Context, Node)
                      end, NodeList),
                case Nodes of
                    [] ->
                        Msg = io_lib:format("(~s) unable to extract any nodes",
                                            [Context]),
                        {error, {bad_value, <<"nodes">>}, iolist_to_binary(Msg)};
                    _ ->
                        K(Nodes)
                end
        end).
  
  extract_node_props(PropsExtractor, Context, NodeStruct) when is_function(PropsExtractor) ->
      PropsExtractor(NodeStruct, Context);
  extract_node_props(Props, Context, {struct, Node}) ->
      R =
          lists:foldl(
            fun ({Prop, Extract}, Acc) ->
                    case proplists:get_value(Prop, Node) of
                        undefined ->
                            ?log_warning("Missing `~s` field in node info:~n~p",
                                         [Prop, Node]),
                            Acc;
                        Value ->
                            case Extract(Value, Context) of
                                {ok, FinalValue} ->
                                    [{Prop, FinalValue} | Acc];
                                {bad_value, Msg} ->
                                    ?log_warning("~s:~n~p", [Msg, Value]),
                                    Acc
                            end
                    end
            end, [], Props),
      [R];
  extract_node_props(_Props, Context, Node) ->
      ?log_warning("(~s) got invalid node info value:~n~p", [Context, Node]),
      [].
  
  props_to_remote_node(Props) ->
      Hostname = proplists:get_value(<<"hostname">>, Props),
  
negative.code:     case proplists:get_value(<<"couchApiBase">>, NodeKV) of
          undefined ->
              ?log_debug("skipping node without couchApiBase: ~p", [NodeKV]),
              {ok, []};
          _ ->
              extract_node_props([{<<"hostname">>, fun extract_string/2},
                                  {<<"couchApiBase">>, fun extract_string/2},
                                  {<<"ports">>, fun extract_object/2},
                                  {<<"couchApiBaseHTTPS">>, {optional, fun extract_string/2}}],
                                 Ctx, {struct, NodeKV})
      end;
  maybe_extract_important_buckets_props(BadNodeStruct, Ctx) ->
      extract_node_props([], Ctx, BadNodeStruct).
  
  maybe_extract_important_buckets_props_basic_test() ->
      Ctx = <<"s">>,
      {ok, []} = maybe_extract_important_buckets_props({struct, []}, Ctx),
      KV0 = [{<<"hostname">>, <<"h">>},
             {<<"couchApiBase">>, <<"ab">>},
             {<<"ports">>, {struct, []}}],
      KV1 = KV0 ++ [{<<"couchApiBaseHTTPS">>, <<"sab">>}],
      Ex0 = lists:keyreplace(<<"ports">>, 1, KV0, {<<"ports">>, []}),
      Ex1 = lists:keyreplace(<<"ports">>, 1, KV1, {<<"ports">>, []}),
      {ok, [Ex0]} = maybe_extract_important_buckets_props({struct, KV0}, Ctx),
      {ok, [Ex1]} = maybe_extract_important_buckets_props({struct, KV1}, Ctx),
      ?assertMatch({error, _, _},
                   maybe_extract_important_buckets_props(
                     {struct, lists:keydelete(<<"hostname">>, 1, KV0)}, Ctx)).
  
  
  remote_bucket_with_bucket(BucketName, BucketObject, OrigRemoteCluster,
  