JuliusBrussee/caveman · error · ValueError

colon

Error message

colon

What it means

ValueError from the hand-rolled JSON walker in _google_wire.py: after decoding an object key, the next non-whitespace character was not ':'. The parser expected the key/value separator at this exact position; the message names the expected token ('colon').

Solutions

  1. Validate the JSON with json.loads first to get a standard parse error message pointing at the malformation
  2. Fix the malformed text by inserting the missing ':' between key and value
  3. Fix the producer/emitter generating broken JSON
  4. Wrap parse() in try/except ValueError and surface a user-friendly invalid-JSON message

Example fix

# before
value = parse('{"model" "gpt"}')  # ValueError: colon
# after
value = parse('{"model": "gpt"}')
Defensive patterns

Strategy: try-catch

Validate before calling

import json
def is_well_formed_json(text):
    try:
        json.loads(text)
        return True
    except json.JSONDecodeError:
        return False

Try / catch

try:
    value = parse(text)
except ValueError as e:
    if str(e) == "colon":
        raise ValueError("Malformed JSON object: expected ':' after key") from e

Prevention

When it happens

Trigger: Parsing malformed JSON where a key is not followed by a colon, e.g. {"a" 1} or {"a" "b"}, via parse().

Common situations: Corrupted or truncated JSON in transit; hand-written JSON missing separators; concatenating JSON fragments; log-extracted JSON with characters stripped.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/4b679a07184de011. Report an issue: GitHub.

Appendix: source

Thrown at packages/middleware/python/caveman_middleware/_google_wire.py:40

        if text[index] == '"':
            value, index = decoder.raw_decode(text, index)
            strings[path] = (start, index, value)
            return value
        if text[index] == "{":
            index += 1
            result = {}
            white()
            if text[index] == "}":
                index += 1
                return result
            while True:
                white()
                key, index = decoder.raw_decode(text, index)
                if type(key) is not str or key in result:
                    raise ValueError("duplicate")
                white()
                if text[index] != ":":
                    raise ValueError("colon")
                index += 1
                result[key] = walk((*path, key), depth + 1)
                white()
                end = text[index]
                index += 1
                if end == "}":
                    return result
                if end != ",":
                    raise ValueError("comma")
        if text[index] == "[":
            index += 1
            result = []
            white()
            if text[index] == "]":
                index += 1
                return result
            while True:
                result.append(walk((*path, len(result)), depth + 1))

View on GitHub (pinned to 3ee70a1026)