infiniflow/ragflow · error · RuntimeError

Credential item {name=} must be of type str, instead receive

Error message

Credential item {name=} must be of type str, instead received {type(name)=}

What it means

Raised by the same get_or_raise helper when a credential value exists but is not a str (e.g. an int, dict, or list). Note that the message formats type(name) instead of type(value), so the reported type is misleading - it prints the type of the key (str), not the offending value. Treat it as a wrong-type credential entry regardless of what the message says.

Source

Thrown at common/data_source/imap_connector.py:206

        ```py
        mail_client.login(..)
        mail_client.logout();
        mail_client.login(..)
        ```

        Therefore, you need a fresh, new instance in order to operate with IMAP. This function gives one to you.

        # Notes
        This function will throw an error if the credentials have not yet been set.
        """

        def get_or_raise(name: str) -> str:
            value = self.credentials.get(name)
            if not value:
                raise RuntimeError(f"Credential item {name=} was not found")
            if not isinstance(value, str):
                raise RuntimeError(f"Credential item {name=} must be of type str, instead received {type(name)=}")
            return value

        username = get_or_raise(_USERNAME_KEY)
        password = get_or_raise(_PASSWORD_KEY)

        mail_client = imaplib.IMAP4_SSL(host=self._host, port=self._port)
        status, _data = mail_client.login(user=username, password=password)

        if status != _IMAP_OKAY_STATUS:
            raise RuntimeError(f"Failed to log into imap server; {status=}")

        return mail_client

    def _load_from_checkpoint(
        self,
        start: SecondsSinceUnixEpoch,
        end: SecondsSinceUnixEpoch,
        checkpoint: ImapCheckpoint,

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Coerce both values to str when building the credentials dict: str(username), str(password).
  2. Fix the upstream config so username/password are stored as plain strings, not nested objects or numbers.
  3. Note the message bug (it prints the type of the key) and inspect the actual dict values when debugging rather than trusting the message.

Example fix

# before
creds = {'username': 1001, 'password': {'value': 'hunter2'}}  # -> RuntimeError type mismatch

# after
creds = {'username': '1001', 'password': 'hunter2'}
Defensive patterns

Strategy: type-guard

Validate before calling

creds = {'username': str(raw.get('username', '')), 'password': str(raw.get('password', ''))}
if not creds['username'] or not creds['password']:
    raise ValueError('IMAP username/password must be non-empty strings')

Type guard

def is_flat_str_dict(creds: dict, keys: tuple) -> bool:
    return all(type(creds.get(k)) is str for k in keys)

Try / catch

try:
    connector.load_from_checkpoint(start, end, checkpoint)
except RuntimeError as e:
    if 'must be of type str' in str(e):
        raise TypeError('IMAP credential values must be plain strings; got a structured value') from e
    raise

Prevention

When it happens

Trigger: The credentials dict contains a numeric username (e.g. 12345) or a nested dict/list as the password for the keys checked in _get_mail_client; any truthy non-string value triggers the branch.

Common situations: Loading credentials from YAML/JSON config where numbers are auto-typed (a numeric mailbox id used as username); wrapping the password in a structure; SDK responses that return nested objects where a flat string was expected.

Related errors


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