Guide

Overpass: “does not support the diff or adiff mode”

Why a history query with [diff:] or [adiff:] fails with JSON or CSV output, and two ways to get the changes.

Overpass writes diffs only as XML. Remove [out:json] or [out:csv(…)] from a query with [diff:] or [adiff:], or write [out:xml], and read the XML. If your code needs JSON, run the query once for each date with [date:] and compare the two answers by type, id and version.

The error

[out:json][adiff:"2024-01-01T00:00:00Z","2025-01-01T00:00:00Z"];
nwr(47.3693,8.5385,47.3707,8.5405)(if:t["amenity"]=="restaurant");
out meta;

Overpass refuses this query before it runs, with HTTP 400 and an HTML page that says:

Error: line 1: static error: The selected output format does not support the diff or adiff mode.

[out:csv(…)] gets the same answer. A diff is a list of <action> elements with an old and a new version, and only the XML output has a form for that.

Fix 1: read the XML

Write [out:xml], or leave out the out setting; XML is the default. Python reads the answer with xml.etree.ElementTree from the standard library:

import xml.etree.ElementTree as ET

root = ET.fromstring(answer)            # the bytes of the response
for action in root.findall("action"):
    old, new = action.find("old/*"), action.find("new/*")
    print(action.get("type"), (new if new is not None else action[0]).get("id"))

Each action is create, modify or delete. With [adiff:], a delete whose new version has visible="false" is a deleted element, and one with visible="true" still exists but no longer matches the query. OpenStreetMap changes in an area has the whole script.

Fix 2: two queries in JSON

Run the same query with [date:] for each of the two dates and compare the elements. With out meta each element has its version, so an edit shows as a change of version:

import json
import os
import urllib.parse
import urllib.request

URL = "https://api.overpass.ch/v1/" + os.environ["OVERPASS_CH_KEY"] + "/interpreter"
QUERY = """[out:json][timeout:60][date:"{date}"];
nw(47.369,8.541,47.376,8.547)(if:t["amenity"]=="restaurant");
out meta center;"""


def at(date):
    data = urllib.parse.urlencode({"data": QUERY.format(date=date)}).encode()
    els = json.loads(urllib.request.urlopen(URL, data=data, timeout=90).read())["elements"]
    return {(e["type"], e["id"]): e for e in els}


a, b = at("2023-01-01T00:00:00Z"), at("2025-01-01T00:00:00Z")
for k in sorted(b.keys() - a.keys()):
    print("added   ", b[k]["tags"].get("name", k))
for k in sorted(a.keys() - b.keys()):
    print("removed ", a[k]["tags"].get("name", k))
edited = [k for k in a.keys() & b.keys() if a[k]["version"] != b[k]["version"]]
print(len(edited), "edited,", len(a.keys() & b.keys()) - len(edited), "unchanged")
added    Da Raffaele
added    Rank
added    Rank
added    Wien Zeile
added    Rising Sun
added    Hirschli
added    roots
added    Restaurant zum weissen Kreuz
removed  Enzian vegan food
removed  Isebähnli
removed  The Butcher
removed  Kormasutra
removed  Öpfelchammer
removed  barfüsser
removed  Bauernschänke
removed  Long Wai
removed  ('node', 9270127717)
removed  ('node', 9870177417)
61 edited, 4 unchanged

The restaurants of the Niederdorf in Zurich from 2023 to 2025. Both queries together took 2.9 seconds. The totals are those of the [adiff:] query on the same area, but this way cannot tell a deleted restaurant from one that is now something else: both are only missing at the second date. To find out, ask for the missing ids at the second date, or use [adiff:].

Good to know

  • [date:] alone works with every output format, JSON and CSV included. Only [diff:] and [adiff:] need XML.
  • The history starts on 12 September 2012. A date before that returns only the elements that nobody edited since.
  • out meta adds the version, the time and the user of each element; without it, the JSON comparison above has no versions to compare.

On overpass.ch

History queries are part of the Medium and Large plans; other plans get HTTP 403 history_not_in_plan. Overpass history queries explains [date:], [diff:] and [adiff:] with examples.