{"record":{"id":"d6b019d84b656915","repo":"infiniflow/ragflow","slug":"unexpected-validation-error-e","errorCode":null,"errorMessage":"Unexpected validation error: {e}","messagePattern":"Unexpected validation error: (.+?)","errorType":"validation","errorClass":"ConnectorValidationError","httpStatus":null,"severity":"error","filePath":"common/data_source/moodle_connector.py","lineNumber":99,"sourceCode":"            raise ConnectorMissingCredentialError(f\"Failed to initialize Moodle client: {e}\")\n\n    def validate_connector_settings(self) -> None:\n        if not self.moodle_client:\n            raise ConnectorMissingCredentialError(\"Moodle client not initialized\")\n\n        try:\n            site_info = self.moodle_client.core.webservice.get_site_info()\n            if not site_info.sitename:\n                raise InsufficientPermissionsError(\"Invalid Moodle API response\")\n        except MoodleException as e:\n            msg = str(e).lower()\n            if \"invalidtoken\" in msg:\n                raise CredentialExpiredError(\"Moodle token is invalid or expired\")\n            if \"accessexception\" in msg:\n                raise InsufficientPermissionsError(\"Insufficient permissions. Ensure web services are enabled and permissions are correct.\")\n            raise ConnectorValidationError(f\"Moodle validation error: {e}\")\n        except Exception as e:\n            raise ConnectorValidationError(f\"Unexpected validation error: {e}\")\n\n    # -------------------------------------------------------------------------\n    # Data loading & polling\n    # -------------------------------------------------------------------------\n\n    def load_from_state(self) -> Generator[list[Document], None, None]:\n        if not self.moodle_client:\n            raise ConnectorMissingCredentialError(\"Moodle client not initialized\")\n\n        logger.info(\"Starting full load from Moodle workspace\")\n        courses = self._get_enrolled_courses()\n        if not courses:\n            logger.warning(\"No courses found to process\")\n            return\n\n        yield from self._yield_in_batches(self._process_courses(courses))\n\n    def poll_source(self, start: SecondsSinceUnixEpoch, end: SecondsSinceUnixEpoch) -> Generator[list[Document], None, None]:","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/common/data_source/moodle_connector.py#L81-L117","documentation":"A ConnectorValidationError raised in validate_connector_settings as the final except branch: get_site_info() threw something other than a MoodleException (connection error, timeout, SSL failure, JSON decode error), and the raw exception is embedded into the message. It is the catch-all for infrastructure-level failures during validation.","triggerScenarios":"Any non-Moodle exception from the client during get_site_info — DNS failure for moodle_url, connection refused, TLS certificate verification error, socket timeout, or a 200 response with a non-JSON body that breaks parsing.","commonSituations":"Wrong/unreachable moodle_url; self-signed cert without proper trust; firewall blocking egress from the indexer; Moodle fronted by a proxy returning HTML; slow site hitting the HTTP client timeout.","solutions":["Read the embedded exception text — it distinguishes DNS ('Name or service not known'), TLS ('certificate verify failed'), timeout, and parse errors.","For TLS issues, import the internal CA into the indexer's trust store (avoid disabling verification in production).","For timeouts, check Moodle health/latency and raise the client's timeout if the site is slow.","Verify network egress from the connector host to <moodle_url>/webservice/rest/server.php with curl."],"exampleFix":"# before\nconnector.validate_connector_settings()  # ConnectorValidationError('Unexpected validation error: <urlopen error ...>')\n\n# after\n# fix reachability / trust first, then surface specifics\ntry:\n    connector.validate_connector_settings()\nexcept ConnectorValidationError as exc:\n    logging.error(\"Moodle validation failed: %s\", exc)\n    raise","handlingStrategy":"try-catch","validationCode":"import socket, ssl, requests\n\ndef moodle_endpoint_reachable(moodle_url: str) -> bool:\n    try:\n        requests.get(moodle_url, timeout=10)\n        return True\n    except (requests.ConnectionError, requests.Timeout, ssl.SSLError, socket.gaierror):\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    connector.validate_connector_settings()\nexcept ConnectorValidationError as exc:\n    msg = str(exc)\n    if 'certificate verify failed' in msg:\n        install_internal_ca()\n    elif 'timed out' in msg or 'Connection' in msg:\n        check_egress_and_moodle_health()\n    else:\n        raise","preventionTips":["Pre-flight network reachability and TLS trust from the indexer host.","Set an explicit HTTP timeout sized to the Moodle site's latency.","Log the embedded exception text in full — it names the infra layer at fault."],"tags":["moodle","network","tls","validation","timeout"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}