infiniflow/ragflow · error · ConnectorMissingCredentialError

Airtable credentials not loaded

Error message

Airtable credentials not loaded

What it means

ConnectorMissingCredentialError raised by AirtableConnector._iter_attachment_entries (common/data_source/airtable_connector.py:56-58). The connector stores its AirtableApi client in self._airtable_client, populated only when credentials are loaded; the attachment-scan generator guards on this and refuses to iterate when no client was ever set, rather than crashing later with an opaque AttributeError. The sister method load_from_state (line ~104) raises the identical error for the same reason.

Source

Thrown at common/data_source/airtable_connector.py:49

    This connector ingests Airtable attachments as raw blobs without
    parsing file content or generating text/image sections.
    """

    def __init__(
        self,
        base_id: str,
        table_name_or_id: str,
        batch_size: int = INDEX_BATCH_SIZE,
    ) -> None:
        self.base_id = base_id
        self.table_name_or_id = table_name_or_id
        self.batch_size = batch_size
        self._airtable_client: AirtableApi | None = None
        self.size_threshold = AIRTABLE_CONNECTOR_SIZE_THRESHOLD

    def _iter_attachment_entries(self) -> Generator[tuple[str, str, str, str, str | None, dict[str, Any]], None, None]:
        if not self._airtable_client:
            raise ConnectorMissingCredentialError("Airtable credentials not loaded")

        table = self.airtable_client.table(self.base_id, self.table_name_or_id)
        records = table.all()

        logging.info(f"Starting Airtable attachment scan for table {self.table_name_or_id}, {len(records)} records found.")

        for record in records:
            record_id = record.get("id")
            fields = record.get("fields", {})
            created_time = record.get("createdTime")

            for field_value in fields.values():
                if not isinstance(field_value, list):
                    continue

                for attachment in field_value:
                    filename = attachment.get("filename")
                    attachment_id = attachment.get("id")

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Load/apply Airtable credentials (API key/personal access token) through the same code path the ingestion service uses before calling load_from_state.
  2. Check self._airtable_client (or the public airtable_client property) is non-None before starting the sync and surface a clear configuration error.
  3. If credentials come from the data-source record, verify that record actually contains the airtable token before scheduling the connector.

Example fix

# before
conn = AirtableConnector(base_id, table)
docs = conn.load_from_state()  # raises
# after
conn = AirtableConnector(base_id, table)
conn.load_credentials(credentials)  # sets _airtable_client
docs = conn.load_from_state()
Defensive patterns

Strategy: validation

Validate before calling

if connector._airtable_client is None:
    raise RuntimeError("Airtable credentials not loaded — call the credential loader before scanning attachments")

Type guard

def airtable_ready(connector) -> bool:
    return connector._airtable_client is not None

Try / catch

from common.data_source.airtable_connector import ConnectorMissingCredentialError
try:
    entries = list(connector._iter_attachment_entries())
except ConnectorMissingCredentialError:
    log.error("data source missing Airtable token; mark sync failed and notify")
    raise

Prevention

When it happens

Trigger: Calling load_from_state (or anything that drives _iter_attachment_entries) on an AirtableConnector that was constructed with only base_id/table_name_or_id but never had credentials applied (the credential-loading path that sets _airtable_client was skipped or failed silently).

Common situations: Building the connector directly in tests/scripts without the credential-loading step the production ingestion service performs; a data-source sync job whose credential fetch returned empty and the code proceeded to load anyway; connector reused after a credential reset.

Related errors


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