← Back to the dataset

UN Security Council vetoes in R

The package holds a dataset of every veto cast in the UN Security Council from 1946 to October 2026. This vignette shows what is in it, how to count vetoes, how to use the roll calls, and how to join the data to country-year and conflict-year panels.

library(unscvetoes)

The data

There are three tables. vetoes has one row per vetoed draft. A draft vetoed by two members, such as China and Russia, is one row; this follows the UN’s own count.

nrow(vetoes)
#> [1] 274
vetoes[vetoes$year == 2026, c("veto_id", "date", "vetoed_by", "topic")]
#>     veto_id       date     vetoed_by
#> 272     272 2026-04-07 China; Russia
#> 273     273 2026-09-17 China; Russia
#> 274     274 2026-10-30        Russia
#>                                               topic
#> 272 Iran: maritime security in the Strait of Hormuz
#> 273        Iran: sanctions Panel of Experts renewal
#> 274                 Western Sahara: MINURSO renewal

Most vetoes fell on draft resolutions. In the early years the Council also voted on parts of drafts, on amendments, on membership applications and on whether a question was procedural. vetoed_item records which.

table(vetoes$vetoed_item)
#> 
#>           amendment         application               draft       oral proposal 
#>                  14                  10                 217                   2 
#>       part of draft procedural question 
#>                  28                   3

veto_votes holds the roll call: one row per Council member per draft, 11 members until 1965 and 15 since. Here is the vote on the 2024 draft on weapons in outer space.

subset(veto_votes, draft_symbol == "S/2024/302", c(member, permanent, vote, veto))
#>              member permanent    vote  veto
#> 3488          China      TRUE abstain FALSE
#> 3489         France      TRUE     yes FALSE
#> 3490         Russia      TRUE      no  TRUE
#> 3491 United Kingdom      TRUE     yes FALSE
#> 3492  United States      TRUE     yes FALSE
#> 3493        Algeria     FALSE     yes FALSE
#> 3494        Ecuador     FALSE     yes FALSE
#> 3495         Guyana     FALSE     yes FALSE
#> 3496          Japan     FALSE     yes FALSE
#> 3497          Malta     FALSE     yes FALSE
#> 3498     Mozambique     FALSE     yes FALSE
#> 3499   Sierra Leone     FALSE     yes FALSE
#> 3500       Slovenia     FALSE     yes FALSE
#> 3501    South Korea     FALSE     yes FALSE
#> 3502    Switzerland     FALSE     yes FALSE

veto_countries has one row per country a draft concerns, with ISO3, Correlates of War and Gleditsch–Ward codes as they stood on the date of the vote.

head(veto_countries[c("date", "country", "iso3c", "cown", "gwno", "vetoed_by")])
#>         date        country iso3c cown gwno vetoed_by
#> 1 1946-02-16         France   FRA  220  220    Russia
#> 2 1946-02-16 United Kingdom   GBR  200  200    Russia
#> 3 1946-02-16        Lebanon   LBN  660  660    Russia
#> 4 1946-02-16          Syria   SYR  652  652    Russia
#> 5 1946-06-18          Spain   ESP  230  230    Russia
#> 6 1946-06-18          Spain   ESP  230  230    Russia

Each draft also carries a short account of what it would have done, the reason the vetoing member gave, and what followed.

cat(vetoes$context[vetoes$veto_id == 254])
#> The United States and Albania tabled a draft that would have condemned Russia's referendums in four occupied Ukrainian regions; the vote came on the day Russia announced their annexation. Russia vetoed it, calling the draft a provocation and saying the votes reflected local will. The vote was 10 in favour, 1 against and 4 abstentions (Brazil, China, Gabon and India). On 12 October 2022 the General Assembly adopted resolution ES-11/4 at its emergency special session.

Counting vetoes

count_vetoes() counts drafts by year, or member vetoes by member. A joint veto counts once in a yearly count and once for each member in a count by member.

count_vetoes("member")
#>   member   n
#> 3 Russia 164
#> 5     US  95
#> 4     UK  32
#> 1  China  23
#> 2 France  18
count_vetoes("member", from = 1990)
#>   member  n
#> 3 Russia 44
#> 5     US 28
#> 1  China 20
#> 2 France  0
#> 4     UK  0

The plot has one square per member veto. It shows the Soviet vetoes of the late 1940s and 1950s, the American vetoes of the 1970s and 1980s, and the rise since 2011.

plot_vetoes(title = NULL)

By decade and member:

by_member <- count_vetoes(c("year", "member"))
by_member$decade <- by_member$year %/% 10 * 10
xtabs(n ~ decade + member, data = by_member)
#>       member
#> decade China France Russia UK US
#>   1940     0      2     46  0  0
#>   1950     1      2     45  2  0
#>   1960     0      0     18  1  0
#>   1970     2      7      7 14 21
#>   1980     0      7      4 15 46
#>   1990     2      0      2  0  6
#>   2000     2      0      4  0 10
#>   2010     9      0     19  0  3
#>   2020     7      0     19  0  9

What the vetoes were about

Region and issue area are coded for every draft, one code each. The issue area follows a fixed order of precedence set out in the codebook.

sort(table(vetoes$issue_area), decreasing = TRUE)
#> 
#>        UN membership and appointments           Use of force and ceasefires 
#>                                    63                                    61 
#> Occupation, territory and settlements Decolonization and self-determination 
#>                                    26                                    22 
#>     Accountability and investigations                      Peace operations 
#>                                    21                                    21 
#>     Political crises and human rights                             Sanctions 
#>                                    21                                    16 
#>    Humanitarian access and protection     Non-proliferation and disarmament 
#>                                    12                                     9 
#>                        Other thematic 
#>                                     2
with(vetoes, table(issue_area, period = ifelse(year < 1990, "1946-89", "1990-2026")))
#>                                        period
#> issue_area                              1946-89 1990-2026
#>   Accountability and investigations          13         8
#>   Decolonization and self-determination      22         0
#>   Humanitarian access and protection          2        10
#>   Non-proliferation and disarmament           5         4
#>   Occupation, territory and settlements      18         8
#>   Other thematic                              0         2
#>   Peace operations                           13         8
#>   Political crises and human rights          15         6
#>   Sanctions                                  11         5
#>   UN membership and appointments             61         2
#>   Use of force and ceasefires                40        21

Using the roll calls

A veto is cast by a permanent member, but elected members sometimes vote with it. These are the elected members that most often voted against a draft that a permanent member vetoed:

with_veto <- subset(veto_votes, vote == "no" & !permanent)
head(sort(table(with_veto$member), decreasing = TRUE), 10)
#> 
#>               Poland        Ukrainian SSR              Bolivia 
#>                   23                   22                    7 
#>               Canada         West Germany               Ceylon 
#>                    5                    5                    4 
#>       Czechoslovakia         South Africa United Arab Republic 
#>                    4                    3                    3 
#>         East Germany 
#>                    2

The number of votes in favour of a vetoed draft gives a rough measure of how isolated the vetoing member was. Since 1990:

recent <- subset(vetoes, year >= 1990)
table(recent$vote_yes)
#> 
#>  9 10 11 12 13 14 
#>  7 10 16  8 19 14
round(tapply(recent$vote_yes, recent$vetoed_by, mean), 1)
#>         China China; Russia        Russia            US 
#>          13.5          11.1          11.8          12.3

Joining country-year data

veto_country_year() collapses the country table to one row per country and year. Join it to any panel keyed on COW or Gleditsch–Ward codes, and set years without a veto to zero.

cy <- veto_country_year()
head(cy)
#>     iso3c cown gwno     country year n_vetoes veto_china veto_france
#> 175   AFG  700  700 Afghanistan 1980        1          0           0
#> 9     ALB  339  339     Albania 1946        1          0           0
#> 14    ALB  339  339     Albania 1947        6          0           0
#> 164   AGO  540  540      Angola 1976        1          0           0
#> 169   AGO  540  540      Angola 1977        1          0           1
#> 183   AGO  540  540      Angola 1981        1          0           0
#>     veto_russia veto_uk veto_us
#> 175           1       0       0
#> 9             1       0       0
#> 14            6       0       0
#> 164           0       0       1
#> 169           0       1       1
#> 183           0       0       1

panel <- expand.grid(cown = c(652, 666, 369), year = 2010:2024)
panel <- merge(panel, cy[c("cown", "year", "n_vetoes")], by = c("cown", "year"), all.x = TRUE)
panel$n_vetoes[is.na(panel$n_vetoes)] <- 0
xtabs(n_vetoes ~ year + cown, data = panel)
#>       cown
#> year   369 652 666
#>   2010   0   0   0
#>   2011   0   1   1
#>   2012   0   2   0
#>   2013   0   0   0
#>   2014   1   1   0
#>   2015   1   0   0
#>   2016   0   2   0
#>   2017   0   5   1
#>   2018   0   1   1
#>   2019   0   2   0
#>   2020   0   2   0
#>   2021   0   0   0
#>   2022   2   1   0
#>   2023   0   1   4
#>   2024   0   0   3

Palestine, Western Sahara and a few historical entities have no COW or Gleditsch–Ward code. Join on iso3c if you need them.

Joining UCDP conflict-year data

Drafts about an armed conflict have a UCDP conflict identifier, ucdp_conflict_id. The code below joins vetoes to the UCDP/PRIO Armed Conflict Dataset, which you download from UCDP.

tmp <- tempfile(fileext = ".zip")
download.file("https://ucdp.uu.se/downloads/ucdpprio/ucdp-prio-acd-261-csv.zip", tmp)
acd <- read.csv(unz(tmp, "UcdpPrioConflict_v26_1.csv"))

v <- subset(vetoes, !is.na(ucdp_conflict_id))
v$n_vetoes <- 1
vy <- aggregate(n_vetoes ~ ucdp_conflict_id + year, data = v, FUN = sum)
names(vy)[1] <- "conflict_id"

acd_v <- merge(acd, vy, by = c("conflict_id", "year"), all.x = TRUE)
acd_v$n_vetoes[is.na(acd_v$n_vetoes)] <- 0
table(intensity = acd_v$intensity_level, veto = acd_v$n_vetoes > 0)

Two cautions. Drafts with ucdp_match == "past" concern a mission or settlement after a conflict ended, such as the UN force in Cyprus, so they have no active conflict-year to join. Vetoes after 2025 fall outside UCDP version 26.1.

The conflicts with the most vetoes:

head(sort(table(vetoes$ucdp_conflict_id), decreasing = TRUE))
#> 
#> 234 299 298 235 336 203 
#>  48  18   9   7   7   6

Joining UN documents

draft_symbol, meeting_record and meeting_number follow UN style (S/2023/970, S/PV.9499). They join to UN Digital Library voting records and to resolution data that keep the symbol. For parts of drafts and amendments, draft_symbol gives the document voted on and draft_note says which part.

vetoes[vetoes$veto_id == 259, c("draft_symbol", "meeting_record", "meeting_number")]
#>     draft_symbol meeting_record meeting_number
#> 259   S/2023/970      S/PV.9499           9499

Citation

Lundgren, Magnus. 2026. UN Security Council Vetoes Dataset. Version 1. University of Gothenburg. Cite a single veto by its veto_id.