OtterMind/Chat2DB · error · ConfigurationError

Prepared QQ notification has an invalid format

Error message

Prepared QQ notification has an invalid format

What it means

Thrown by notify_qq._read_prepared_message when the parsed JSON is not a Mapping or its 'version' field is not 1. The reader expects a versioned envelope object; a JSON array, scalar, or an object missing/wrong 'version' is rejected.

Source

Thrown at script/github/notify_qq.py:253

                "event_name": event_name,
                "repository": repository,
                "message": message,
            },
            ensure_ascii=False,
        ),
        encoding="utf-8",
    )


def _read_prepared_message(path: Path, repository: str) -> tuple[str, str]:
    if not path.is_file() or path.stat().st_size > 4096:
        raise ConfigurationError("Prepared QQ notification is missing or too large")
    try:
        envelope = json.loads(path.read_text(encoding="utf-8"))
    except (OSError, UnicodeError, json.JSONDecodeError) as error:
        raise ConfigurationError("Prepared QQ notification is not valid JSON") from error
    if not isinstance(envelope, Mapping) or envelope.get("version") != 1:
        raise ConfigurationError("Prepared QQ notification has an invalid format")
    if envelope.get("repository") != repository:
        raise ConfigurationError("Prepared QQ notification repository does not match")
    event_name = str(envelope.get("event_name") or "")
    if event_name not in COLLECTED_EVENT_NAMES:
        raise ConfigurationError("Prepared QQ notification event is not allowed")
    message = envelope.get("message")
    if not isinstance(message, str) or not message or len(message) > 900:
        raise ConfigurationError("Prepared QQ notification message is invalid")
    if re.search(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]", message):
        raise ConfigurationError("Prepared QQ notification contains control characters")
    if re.search(r"(?i)\[CQ:", message):
        raise ConfigurationError("Prepared QQ notification contains a OneBot CQ code")
    return event_name, message


def _event_detail(event_name: str, action: str, payload: Mapping[str, Any]) -> str:
    if action in {"labeled", "unlabeled"}:
        label = payload.get("label") or {}

View on GitHub (pinned to 5ee1e990e7)

Solutions

  1. Regenerate the file with the current producer (_write_prepared_message) so it includes "version": 1 and a Mapping shape.
  2. If the schema evolves, bump and handle the new version in the reader instead of removing the version field.
  3. Ensure only the sanctioned producer writes the drop file.

Example fix

# before: file content
{"event_name": "pull_request_review", "repository": "x", "message": "..."}
# missing version -> has an invalid format

# after
{"version": 1, "event_name": "pull_request_review", "repository": "x", "message": "..."}
Defensive patterns

Strategy: validation

Validate before calling

envelope = json.loads(raw)
if not isinstance(envelope, Mapping) or envelope.get("version") != 1:
    raise ConfigurationError("Envelope must be a version-1 object")

Type guard

def is_valid_envelope(envelope: object) -> bool:
    return (isinstance(envelope, Mapping)
            and envelope.get("version") == 1
            and isinstance(envelope.get("message"), str))

Prevention

When it happens

Trigger: The drop file contains valid JSON but is an array/scalar, or an object whose 'version' key is absent, null, or an integer other than 1.

Common situations: A producer from an older/newer script version wrote a different envelope shape; manual editing of the file; another tool writing a JSON object without the version field.

Related errors


AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14). Data as JSON: /api/errors/eb240798399d1f4f. Report an issue: GitHub.