OtterMind/Chat2DB · error · ConfigurationError

Missing required GitHub Actions secrets: {missing}

Error message

Missing required GitHub Actions secrets: {missing}

What it means

Raised by _required_environment (notify_qq.py:575) as a ConfigurationError when one or both of QQ_RELAY_URL and QQ_RELAY_TOKEN are empty/unset. The message lists the missing names. This runs only on the live-send path (after dry-run/output checks), so collect and dry-run flows do not require them.

Source

Thrown at script/github/notify_qq.py:575

    delivery_id: str,
    content: str,
) -> dict[str, Any]:
    return _post_json(
        _validated_relay_url(relay_url),
        {
            "repository": repository,
            "delivery_id": delivery_id,
            "message": content,
        },
        {"Authorization": f"Bearer {relay_token}"},
    )


def _required_environment() -> tuple[str, str]:
    names = ("QQ_RELAY_URL", "QQ_RELAY_TOKEN")
    missing = [name for name in names if not os.environ.get(name)]
    if missing:
        raise ConfigurationError("Missing required GitHub Actions secrets: " + ", ".join(missing))
    return tuple(os.environ[name] for name in names)  # type: ignore[return-value]


def _is_true(value: str | None) -> bool:
    return str(value or "").strip().lower() in {"1", "true", "yes", "on"}


def main() -> int:
    event_path = Path(os.environ.get("GITHUB_EVENT_PATH", ""))
    if not event_path.is_file():
        raise ConfigurationError("GITHUB_EVENT_PATH does not point to an event payload")

    with event_path.open(encoding="utf-8") as event_file:
        payload = json.load(event_file)

    event_name = os.environ.get("GITHUB_EVENT_NAME", "")
    repository = os.environ.get("GITHUB_REPOSITORY", "OtterMind/Chat2DB")
    actor = os.environ.get("GITHUB_ACTOR", "unknown")

View on GitHub (pinned to 5ee1e990e7)

Solutions

  1. Create QQ_RELAY_URL and QQ_RELAY_TOKEN as repository (or environment) secrets.
  2. Map them into the step env: QQ_RELAY_URL: ${{ secrets.QQ_RELAY_URL }}.
  3. Check exact secret names for typos and confirm they are non-empty.
  4. Use QQ_DRY_RUN=true or QQ_MESSAGE_OUTPUT_PATH during setup to avoid needing them until ready.

Example fix

# before: env: { QQ_RELAY_URL: ${{ secrets.RELAY_URL }} }
# after:  env: { QQ_RELAY_URL: ${{ secrets.QQ_RELAY_URL }}, QQ_RELAY_TOKEN: ${{ secrets.QQ_RELAY_TOKEN }} }
Defensive patterns

Strategy: validation

Validate before calling

missing = [n for n in ("QQ_RELAY_URL", "QQ_RELAY_TOKEN") if not os.environ.get(n)]
if missing:
    raise SystemExit("missing secrets: " + ", ".join(missing))

Prevention

When it happens

Trigger: The notifier reaches the send step but the GitHub Actions secrets QQ_RELAY_URL and/or QQ_RELAY_TOKEN were not exposed to the job, or were set to empty strings.

Common situations: Secrets not created in the repo; secrets created but not referenced in the job's env; secrets named differently (typo); secrets inherited conditionally from a different environment; running the workflow in a fork without the secrets.

Related errors


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