---
title: "Valhalla"
description: "Contributor to Valhalla, a high-performance routing engine built on OpenStreetMap data. My work focused on Python interoperability, OpenLR support, developer experience, and infrastructure improvements."
canonical_url: "https://www.victoryanson.com/work/valhalla"
last_updated: "2026-09-17T20:55:44.606Z"
---

## TL;DR

Contributed to Valhalla, an OSM routing engine, while preparing my GSoC 2026 application. Started with a small Docker improvement before moving into OpenLR Python bindings and the wider Python binding architecture. Along the way, I participated in upstream design discussions, reviewed changes, investigated CI failures, and learned how to contribute to an established FOSS project.

<table-of-contents exclude="Table of Contents, TL;DR" :max-depth="2">



</table-of-contents>

## Background

During GSoC 2026 I applied for a [project suggestion](https://wiki.openstreetmap.org/wiki/Google_Summer_of_Code/2026/Project_ideas#Routing) by OSM member Simon Poole. The gist was to integrate an existing platform (`closures.osm.ch`) more closely with one of the OSM routing engines. With the project already using Valhalla as its main routing engine, it made it the obvious place to start. Although Valhalla wasn't the target project of my GSoC application, I decided to contribute upstream alongside my preparations. I did this partly to become familiar with the codebase, partly to contribute something useful, and partly to prove to myself that I could actually navigate an established FOSS project rather than just build things in isolation.

<steps level="2">

## Docker Version Logging

My first contribution came in the form of a 6-line patch. Looking back it was nothing much, at the time however, following the then-unfamiliar FOSS ettiquette was quite stressful. The patch was an enhancement to an earlier <badge>

good-first-issue

</badge>

 regarding a quality of life feature during the Docker container startup. The idea being that background a daemon that can be queried through a CLI which can return the running Valhalla version.

```bash
valhalla_service --version # prints "x.x.x-commit_hash"
```

My patch added the following lines to the start of `docker/scripts/docker-entrypoint.sh`:

```bash
# logging valhalla version
VALHALLA_VERSION=$(valhalla_service --version | tr -d '\n')

echo ""
echo "===================="
echo "= Valhalla version ="
echo "===================="
echo "Valhalla version: ${VALHALLA_VERSION}"
echo ""
```

I know, spectacular. I nonetheless, got some feedback from the maintainers pointing out that repeating "Valhalla" in the heading and the body would make the file slightly less "greppable". This gave me the opportunity to edit my work and follow up on my submission. After deleting the heading altogether the PR was approved and merged into the master branch for release in `3.6.3`.

<card-group>
<card icon="octicon:issue-opened-16" title="Issue #5721" to="https://github.com/valhalla/valhalla/issues/5721" target="_blank">

Include Valhalla version in Docker container startup logs

</card>

<card icon="boxicons:git-pull-request" title="Pull Request #5884" to="https://github.com/valhalla/valhalla/pull/5884" target="_blank">

docker-entrypoint: display Valhalla version on container start

</card>
</card-group>

## GSoC Proposal

As mentioned before, Valhalla played a crucial role in my GSoC proposal despite it not being the target project. In short, my idea involved creating a containerized sidecar service to run alongside Valhalla which would fetch, decode, and inject live traffic data into Valhalla's live traffic layer. Having scoured previous issues and discussions on the topic and having a rough proposal in mind I decided to float it to the maintainers on the GitHub discussions tab.

To my relief, the maintainers reacted cordially, asking genuine technical questions and pointing out important constraints. Importantly however, they mentioned that they like to see GSoC candidates reason independently, suggesting I should elaborate my proposal without expecting too much of their input. Honestly, the whole thing was quite humbling in a good way. I can say it shed a positive light on the FOSS community to me. Where else do domain experts give you truly engaging feedback for free? All in all, I got what I needed which allowed me to continue the preparations.

From a technical perspective, the pipeline contained in the proposed `closure-sync` sidecar service would: ingest live traffic data, decode the provider-specific feed into OpenLR location references, resolve those references against Valhalla’s OSM-derived graph, and inject the resulting speed/closure information into Valhalla’s live-traffic layer. My goal was to keep the traffic ingestion and decoding logic isolated from the routing engine itself while providing Valhalla with continuously updated, graph-referenced traffic data.

My blog post linked below contains a link to the full GSoC proposal.

<card-group>
<card icon="tabler:article" title="Blog Post" to="/blog/gsoc-2026-a-hopeful-rejection">

GSoC 2026: A Hopeful Rejection

</card>

<card icon="octicon:comment-discussion-16" title="Discussion #5944" to="https://github.com/valhalla/valhalla/discussions/5944" target="_blank">

Native Dynamic Road Closure Support

</card>
</card-group>

## Python OpenLR Module

After the GSoC rejection, I had steadily grown familiar with the OpenLR format. Wanting to keep contributing to the project, I decided to go through with one of my GSoC milestones and propose an OpenLR module for the Python API. The main motivation was not work against the depedency hell that is the Python ecosystem, and expose the internal encoding/decoding OpenLR functionality already present in Valhalla (`baldr/openlr.h`).

First I brought up the idea in a separate "ideas" discussion. Once again, I got very insightful feedback, going back and forth on architectural considerations and how the whole thing should fit into the existing Python bindings. With the idea validated, I opened an issue for continuity sake and started work on my PR.

The bindings would live in `src/bindings/python/src/openlr.cc` and would expose the OpenLR class and its member data and functions. The entire thing was done with nanobind as was the pre-established Valhalla standard for Python bindings.

Some notable bindings include:

- `to_base64` and `to_binary` encoding functions (returning `str` and `bytes` respectively)
- `LocationReferencePoint` and `PointLL` data structures
- `SideOfTheRoad` `Orientation`, and `FormOfWay` enums

While the PR was conceptually approved, it sparked a discussion on a potential redo of the internal Python binding structure as a whole. Because of this the PR was left unmerged and the focus was moved to the breaking redesign of the Python bindings. At this point, I will get back to the PR and adapt the OpenLR bindings to the newly established structure.

<card-group>
<card icon="octicon:comment-discussion-16" title="Discussion #6035" to="https://github.com/valhalla/valhalla/discussions/6035" target="_blank">

Python bindings for OpenLR

</card>

<card icon="octicon:issue-opened-16" title="Issue #6037" to="https://github.com/valhalla/valhalla/issues/6037" target="_blank">

OpenLR Python bindings

</card>

<card icon="boxicons:git-pull-request" title="Pull Request #6087" to="https://github.com/valhalla/valhalla/pull/6087" target="_blank">

feat: openlr python bindings

</card>
</card-group>

## Python Binding Restructuring

After being encouraged by the maintainers, I started the conversation on what the Python binding rework could look like. The main problem I identified was that the Python bindings weren't thought out from the start to accommodate increasingly more utilities being exposed through the API. Every new addition therefore felt bolted on and implementations started to diverge and feel disjointed.

My proposed solution was to unify the bindings extension approach by grouping them by their corresponding C++ namespaces.

```plaintext [Example: Midgard Python module exposes bindings to the data structures as organized in the wider repository]
.  
├── midgard
│ ├── PointLL  
│ ├── Heading  
│ ├── Curvature  
│ └── ...
```

My proposal was generally well received but led to some interesting discussions as to what extent the Valhalla bindings should mirror the C++ structure. I argued that bindings are an opportunity to provide useful language-specific abstractions, rather than necessarily exposing every operation exactly as it exists internally in C++. More specifically, I defended convenience functions where the underlying C++ operation is cumbersome to express from Python. The maintainer initially preferred keeping the bindings almost entirely aligned with the C++ API to minimize maintenance and conceptual overhead. After discussing the trade-offs however, they reconsidered and agreed that the API should be consistent in what it exposes rather than having some functionality arbitrarily available only through the bindings.

During the actual PR review I was able to point out some minor improvements, and after approval from another org member the PR was merged.

### Segfault Bug Identification

During the review I also noticed that the new Python test suite was causing process-killing segfaults on my macOS ARM64 setup, particularly around the `test_get_tile_ids_from_ring_*` tests. Initially I wasn't sure whether this was related to an mmap/BUS errors the maintainers had already been dealing with. Just to make sure I wasn't falsely attributing the errors to the PR I kept investigating.

Eventually I found that the segfaults were already acknowledged elsewhere in the project, meaning they weren't caused by the restructuring itself. Rather than blocking the PR, I suggested adding platform-specific guardrails to prevent the tests from killing the entire Python process. More importantly, I checked the OSX CI logs and found that the exact same failure was happening there. The Python test process was silently terminating halfway through the test suite, but the CI job wasn't detecting the failure because the test output was piped through `tee`.

I also found a separate Python related `KeyError` error in the CI. This turned out to expose a broader CI problem, namely the Python tests were not reliably surfacing process-level crashes on OSX. The maintainer subsequently acknowledged the issue and opened a separate issue to address Python test execution in CI.

<collapsible>

*VictorYanson commented on Jun 19*

> Ok so after investigating I couldn’t find out why the segfault were happening in the first place, however I did find them in the CI logs. Look at line 1205 of the `Run Tests` job in >the `Build OSX & Python wheels` check. It starts running all the tests and quits silently half way through right in the same spot as on my local system.
> 
> ```plaintext
> 2026-06-14T19:32:46.5585100Z test_get_tile_ids_from_bbox (test_graph_utils.TestBindings.test_get_tile_ids_from_bbox) ... ok
> 2026-06-14T19:32:46.5586200Z test_get_tile_ids_from_ring_auto_close (test_graph_utils.TestBindings.test_get_tile_ids_from_ring_auto_close)
> 2026-06-14T19:32:46.5586790Z Open ring (last != first) should be auto-closed. ... [ 34%] Built target gurka_closure_penalty
> 2026-06-14T19:32:46.5587250Z [ 34%] Built target run-python_valhalla
> ```
> 
> I guess because the test runner pipes the output through [tee](https://github.com/valhalla/valhalla/blob/8315d324f8d179b6477c3152e994e134a54df50f/test/CMakeLists.txt#L480) the CI only >checks if tee succeeded while completely missing the fact that python crashed.
> 
> <details>
> <summary>
> 
> I also spotted a separate python key error locally during the config load which is reflected in the CI logs as well.
> 
> </summary>
> 
> Local:
> 
> ```bash
> ======================================================================
> ERROR: test_change_config (test_actor.TestBindings.test_change_config)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>  File ".../test_actor.py", line 186, in test_change_config
>    config = get_config(self.extract_path, self.tiles_path)
>  File ".../valhalla/config.py", line 57, in get_config
>    config["mjolnir"]["logging"]["type"] = "std_out" if verbose else ""
> KeyError: 'logging'
> ```
> 
> CI (lines 1149-1151 in `Build OSX & Python wheels` > `Run Tests`):
> 
> ```plaintext
> 2026-06-14T19:32:46.0710400Z test_change_config (test_actor.TestBindings.test_change_config) ... ERROR
> 2026-06-14T19:32:46.0810630Z test_config (test_actor.TestBindings.test_config) ... ERROR
> 2026-06-14T19:32:46.0912660Z test_config_actor (test_actor.TestBindings.test_config_actor) ... ERROR
> ```
> 
> </details>
> 
> Anyways, the code changes in last commit look totally fine to me. I’ll mark it for approval!

</collapsible>

<card-group>
<card icon="octicon:comment-discussion-16" title="Discussion #6069" to="https://github.com/valhalla/valhalla/discussions/6096" target="_blank">

re-design python binding structure

</card>

<card icon="boxicons:git-pull-request" title="Pull Request #6133" to="https://github.com/valhalla/valhalla/pull/6133" target="_blank">

BREAKING(python): change layout of bindings, no signature change

</card>

<card icon="boxicons:git-pull-request" title="Pull Request #6179" to="https://github.com/valhalla/valhalla/pull/6179" target="_blank">

fix(release): 3.8.0 didn't land on pypi

</card>
</card-group>
</steps>
