{"record":{"id":"1ecf2087b8cca531","repo":"infiniflow/ragflow","slug":"moodle-client-not-initialized","errorCode":null,"errorMessage":"Moodle client not initialized","messagePattern":"Moodle client not initialized","errorType":"validation","errorClass":"ConnectorMissingCredentialError","httpStatus":null,"severity":"error","filePath":"common/data_source/moodle_connector.py","lineNumber":85,"sourceCode":"        for batch in batch_generator(generator, self.batch_size):\n            yield batch\n\n    def load_credentials(self, credentials: dict[str, Any]) -> None:\n        token = credentials.get(\"moodle_token\")\n        if not token:\n            raise ConnectorMissingCredentialError(\"Moodle API token is required\")\n\n        try:\n            self.moodle_client = MoodleClient(self.moodle_url + \"/webservice/rest/server.php\", token)\n            self.moodle_client.core.webservice.get_site_info()\n        except MoodleException as e:\n            if \"invalidtoken\" in str(e).lower():\n                raise CredentialExpiredError(\"Moodle token is invalid or expired\")\n            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    # -------------------------------------------------------------------------","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/common/data_source/moodle_connector.py#L67-L103","documentation":"A ConnectorMissingCredentialError raised at the start of validate_connector_settings when self.moodle_client is None, i.e. load_credentials was never called or failed before the client was assigned. Validation cannot proceed because it needs the live client to call get_site_info.","triggerScenarios":"Calling validate_connector_settings() on a freshly constructed MoodleConnector, or after a load_credentials attempt that raised (e.g. invalid token) leaving moodle_client unset.","commonSituations":"Validation-first orchestration that assumes the connector self-initializes; retry logic that calls validate after a failed load; unit tests instantiating the connector directly.","solutions":["Call load_credentials(credentials) successfully before validate_connector_settings().","If load_credentials raised CredentialExpiredError/ConnectorMissingCredentialError, fix the token first — validation will keep failing until then.","Order operations: construct -> load_credentials -> validate_connector_settings."],"exampleFix":"# before\nconnector = MoodleConnector(...)\nconnector.validate_connector_settings()  # raises ConnectorMissingCredentialError('Moodle client not initialized')\n\n# after\nconnector = MoodleConnector(...)\nconnector.load_credentials({'moodle_token': token})\nconnector.validate_connector_settings()","handlingStrategy":"validation","validationCode":"if not getattr(connector, \"moodle_client\", None):\n    connector.load_credentials(credentials)  # validation needs a live client","typeGuard":"def moodle_ready(conn) -> bool:\n    return getattr(conn, \"moodle_client\", None) is not None","tryCatchPattern":null,"preventionTips":["Enforce the construct -> load_credentials -> validate order in one shared factory.","Treat 'Moodle client not initialized' as a call-order bug; never catch-and-continue."],"tags":["moodle","connector","initialization","credentials","validation"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}