infiniflow/ragflow · error · InsufficientPermissionsError

Invalid Moodle API response

Error message

Invalid Moodle API response

What it means

An InsufficientPermissionsError raised in validate_connector_settings when the get_site_info() call succeeds but the response has an empty sitename. The connector treats a site-info response without a sitename as structurally invalid — a well-formed Moodle answer always includes sitename, so its absence signals a gateway/SSO interception or a broken web-service response rather than a permission scope issue per se.

Source

Thrown at common/data_source/moodle_connector.py:90

        if not token:
            raise ConnectorMissingCredentialError("Moodle API token is required")

        try:
            self.moodle_client = MoodleClient(self.moodle_url + "/webservice/rest/server.php", token)
            self.moodle_client.core.webservice.get_site_info()
        except MoodleException as e:
            if "invalidtoken" in str(e).lower():
                raise CredentialExpiredError("Moodle token is invalid or expired")
            raise ConnectorMissingCredentialError(f"Failed to initialize Moodle client: {e}")

    def validate_connector_settings(self) -> None:
        if not self.moodle_client:
            raise ConnectorMissingCredentialError("Moodle client not initialized")

        try:
            site_info = self.moodle_client.core.webservice.get_site_info()
            if not site_info.sitename:
                raise InsufficientPermissionsError("Invalid Moodle API response")
        except MoodleException as e:
            msg = str(e).lower()
            if "invalidtoken" in msg:
                raise CredentialExpiredError("Moodle token is invalid or expired")
            if "accessexception" in msg:
                raise InsufficientPermissionsError("Insufficient permissions. Ensure web services are enabled and permissions are correct.")
            raise ConnectorValidationError(f"Moodle validation error: {e}")
        except Exception as e:
            raise ConnectorValidationError(f"Unexpected validation error: {e}")

    # -------------------------------------------------------------------------
    # Data loading & polling
    # -------------------------------------------------------------------------

    def load_from_state(self) -> Generator[list[Document], None, None]:
        if not self.moodle_client:
            raise ConnectorMissingCredentialError("Moodle client not initialized")

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Verify moodle_url is the Moodle root (e.g. https://moodle.org) and that /webservice/rest/server.php is reachable.
  2. Call the web service manually: curl '<moodle_url>/webservice/rest/server.php?wstoken=TOKEN&wsfunction=core_webservice_get_site_info&moodlewsrestformat=json' and inspect the JSON for sitename.
  3. If the raw response lacks sitename, fix the Moodle web-services configuration or the proxy in front of it.

Example fix

# before
connector = MoodleConnector(moodle_url='https://org.example/sso')  # proxy answers, sitename empty
connector.load_credentials(creds)
connector.validate_connector_settings()  # InsufficientPermissionsError('Invalid Moodle API response')

# after
connector = MoodleConnector(moodle_url='https://moodle.org')  # real Moodle root
connector.load_credentials(creds)
connector.validate_connector_settings()
Defensive patterns

Strategy: validation

Validate before calling

import requests

def moodle_site_info_ok(moodle_url: str, token: str) -> bool:
    r = requests.get(
        f"{moodle_url}/webservice/rest/server.php",
        params={"wstoken": token, "wsfunction": "core_webservice_get_site_info", "moodlewsrestformat": "json"},
        timeout=10,
    )
    data = r.json()
    return bool(data.get("sitename"))

Try / catch

try:
    connector.validate_connector_settings()
except InsufficientPermissionsError as exc:
    if "Invalid Moodle API response" in str(exc):
        check_proxy_and_url(connector.moodle_url)  # structural response problem
    else:
        fix_web_service_permissions()

Prevention

When it happens

Trigger: get_site_info() returns 200 with an object whose sitename is empty/None — e.g. a proxy returning an empty shell response, a non-Moodle endpoint answering at moodle_url, or a Moodle plugin/version returning a degenerate payload.

Common situations: moodle_url pointing at the wrong path or a reverse proxy login page that happens to parse; Moodle version with web services partially disabled returning an empty info object; SAML/SSO fronting that rewrites responses.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/65469bdc980254be. Report an issue: GitHub.