GET /yaml
Returns YAML documents that exploit the YAML 1.1 vs 1.2 split and parser ambiguity. Default sends the Norway problem: bare `NO/YES/ON/OFF` scalars that YAML 1.1 parsers coerce to booleans while YAML 1.2 parsers leave as strings. Use ?mode= to isolate other violations: recursive anchors, duplicate keys, or tag lies.
mode
norway-problem (default; bare NO/YES/ON/OFF scalars; YAML 1.1 parsers like Go yaml.v2 and older PyYAML coerce to booleans, YAML 1.2 parsers leave as strings; mixed-version pipelines disagree on the type of every value), anchor-cycle (recursive anchor reference `&a` referencing `*a`; parsers without cycle detection follow references until stack or heap is exhausted), duplicate-keys (key `host` appears twice; spec leaves behavior application-defined; parsers variously take first, take last, or error; schema validators almost always reject), tag-lie (explicit `!!int` tag applied to the string `three-point-five`; strict parsers raise a tag resolution error, loose parsers store the raw value and continue silently).
control Compare against the well-formed counterpart: not.catastrophic.io/yaml side-by-side
build a request:
expect: An application/yaml response with one parser-adversity pattern. Mixed-version pipelines disagree on the type of every value; the `note` is in the X-Chaos-Yaml-Note response header.
curl -si 'https://chaos.catastrophic.io/yaml?mode=norway-problem'
# pip install pyyaml ruamel.yaml
import urllib.request, yaml
resp = urllib.request.urlopen("https://chaos.catastrophic.io/yaml?mode=norway-problem")
print("Content-Type:", resp.headers.get("Content-Type"))
print("X-Chaos-Yaml-Mode:", resp.headers.get("X-Chaos-Yaml-Mode"))
print("X-Chaos-Yaml-Note:", resp.headers.get("X-Chaos-Yaml-Note"))
text = resp.read().decode()
try:
# safe_load uses YAML 1.1 in older PyYAML; the Norway problem surfaces here.
parsed = yaml.safe_load(text)
print("parsed:", parsed)
except yaml.YAMLError as e:
print("parser rejected:", e)
// npm: js-yaml (YAML 1.2)
import yaml from "js-yaml";
const res = await fetch("https://chaos.catastrophic.io/yaml?mode=norway-problem");
console.log("Content-Type:", res.headers.get("content-type"));
console.log("X-Chaos-Yaml-Mode:", res.headers.get("x-chaos-yaml-mode"));
console.log("X-Chaos-Yaml-Note:", res.headers.get("x-chaos-yaml-note"));
const text = await res.text();
try {
console.log("parsed:", yaml.load(text));
} catch (e) {
console.log("parser rejected:", e.message);
}
package main
// go get gopkg.in/yaml.v2 (YAML 1.1 — sees Norway problem)
// go get gopkg.in/yaml.v3 (YAML 1.2)
import (
"fmt"
"io"
"net/http"
"gopkg.in/yaml.v3"
)
func main() {
resp, _ := http.Get("https://chaos.catastrophic.io/yaml?mode=norway-problem")
defer resp.Body.Close()
raw, _ := io.ReadAll(resp.Body)
fmt.Println("Content-Type:", resp.Header.Get("Content-Type"))
fmt.Println("X-Chaos-Yaml-Mode:", resp.Header.Get("X-Chaos-Yaml-Mode"))
var out map[string]any
if err := yaml.Unmarshal(raw, &out); err != nil {
fmt.Println("unmarshal rejected:", err)
} else {
fmt.Println("decoded keys:", out)
}
}
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking"] }
// serde_yaml = "0.9" (YAML 1.2)
fn main() -> Result<(), Box> {
let resp = reqwest::blocking::get("https://chaos.catastrophic.io/yaml?mode=norway-problem")?;
println!("Content-Type: {:?}", resp.headers().get("content-type"));
println!("X-Chaos-Yaml-Mode: {:?}", resp.headers().get("x-chaos-yaml-mode"));
let text = resp.text()?;
match serde_yaml::from_str::(&text) {
Ok(v) => println!("parsed: {:?}", v),
Err(e) => println!("parser rejected: {}", e),
}
Ok(())
}
// SnakeYAML on the classpath (YAML 1.1 by default).
import java.net.URI;
import java.net.http.*;
import org.yaml.snakeyaml.Yaml;
public class YamlChaos {
public static void main(String[] args) throws Exception {
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(URI.create("https://chaos.catastrophic.io/yaml?mode=norway-problem")).build();
var resp = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println("Content-Type: " +
resp.headers().firstValue("Content-Type").orElse(""));
System.out.println("X-Chaos-Yaml-Mode: " +
resp.headers().firstValue("X-Chaos-Yaml-Mode").orElse(""));
try {
Object parsed = new Yaml().load(resp.body());
System.out.println("parsed: " + parsed);
} catch (Exception e) {
System.out.println("parser rejected: " + e.getMessage());
}
}
}
// NuGet: YamlDotNet (YAML 1.2)
using YamlDotNet.Serialization;
using var client = new HttpClient();
var resp = await client.GetAsync("https://chaos.catastrophic.io/yaml?mode=norway-problem");
Console.WriteLine($"Content-Type: {resp.Content.Headers.ContentType}");
Console.WriteLine($"X-Chaos-Yaml-Mode: " +
$"{resp.Headers.GetValues("X-Chaos-Yaml-Mode").FirstOrDefault()}");
var text = await resp.Content.ReadAsStringAsync();
try {
var parsed = new Deserializer().Deserialize# YAML.safe_load uses Psych (YAML 1.1)
require "net/http"
require "yaml"
uri = URI("https://chaos.catastrophic.io/yaml?mode=norway-problem")
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
res = http.get(uri.request_uri)
puts "Content-Type: #{res['Content-Type']}"
puts "X-Chaos-Yaml-Mode: #{res['X-Chaos-Yaml-Mode']}"
puts "X-Chaos-Yaml-Note: #{res['X-Chaos-Yaml-Note']}"
begin
parsed = YAML.unsafe_load(res.body)
puts "parsed: #{parsed.inspect}"
rescue => e
puts "parser rejected: #{e.message}"
end
end
# PowerShell-Yaml (Install-Module powershell-yaml)
$r = Invoke-WebRequest -Uri 'https://chaos.catastrophic.io/yaml?mode=norway-problem'
"Content-Type: $($r.Headers['Content-Type'])"
"X-Chaos-Yaml-Mode: $($r.Headers['X-Chaos-Yaml-Mode'])"
"X-Chaos-Yaml-Note: $($r.Headers['X-Chaos-Yaml-Note'])"
try {
$parsed = ConvertFrom-Yaml $r.Content
"parsed keys: $($parsed.Keys -join ', ')"
} catch {
"parser rejected: $_"
}
headers
body