infiniflow/ragflow · error · Error

main() returned a non-JSON-serializable value.

Error message

main() returned a non-JSON-serializable value.

What it means

load_credentials expects the credential JSON to contain the primary-admin key (DB_CREDENTIALS_PRIMARY_ADMIN_KEY). Its absence raises this ValueError, aborting credential loading. The primary admin email is the identity used for delegated Drive access and is mandatory regardless of OAuth vs service-account auth.

Source

Thrown at internal/agent/sandbox/result_protocol.go:117

	// template-literal escapes only on the JS side. We pass them
	// through as-is.
	return code + `

const __ragflowArgsB64 = "` + argsB64 + `";
const __ragflowArgs = JSON.parse(Buffer.from(__ragflowArgsB64, 'base64').toString('utf8'));

(async () => {
  const __ragflowMain = typeof main !== 'undefined' ? main : module.exports && module.exports.main;
  if (typeof __ragflowMain !== 'function') {
    throw new Error('main() must be defined or exported.');
  }
  const output = await Promise.resolve(__ragflowMain(__ragflowArgs));
  if (typeof output === 'undefined') {
    throw new Error('main() must return a value. Use null for an empty result.');
  }
  const payload = JSON.stringify({ present: true, value: output, type: 'json' });
  if (typeof payload === 'undefined') {
    throw new Error('main() returned a non-JSON-serializable value.');
  }
  console.log('` + resultMarkerPrefix + `' + Buffer.from(payload, 'utf8').toString('base64'));
})();
`
}

// ExtractStructuredResult scans stdout for the marker line, decodes
// the JSON payload after it, and returns the user-visible stdout
// (with the marker line removed) plus the parsed structured result.
//
// The Python side returns `(cleaned_stdout, structured_result_dict)`.
// On Go the dict is `map[string]any`.
//
// Edge cases (matching the Python implementation):
//   - empty stdout → ("", empty map).
//   - multiple marker lines → only the LAST one wins (later result
//     overrides earlier). The Python implementation does the same
//     because the loop overwrites `structured_result`.

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Find the expected key name (DB_CREDENTIALS_PRIMARY_ADMIN_KEY, typically 'primary_admin_email') and add it to the credential JSON with the Workspace admin's email
  2. Use the UI's credential flow rather than hand-crafting JSON so the key is populated
  3. If migrating, re-run the credential creation step instead of copying partial payloads

Example fix

# before
credentials = {"google_drive_tokens": {"refresh_token": "..."}}
connector.load_credentials(credentials)  # ValueError

# after
credentials = {
    "google_drive_tokens": {"refresh_token": "..."},
    "primary_admin_email": "admin@acme.com",
}
connector.load_credentials(credentials)
Defensive patterns

Strategy: validation

Validate before calling

PRIMARY_ADMIN_KEY = "primary_admin_email"  # DB_CREDENTIALS_PRIMARY_ADMIN_KEY

def credential_has_admin_key(creds: dict) -> bool:
    return PRIMARY_ADMIN_KEY in creds and "@" in str(creds[PRIMARY_ADMIN_KEY])

Type guard

from typing import TypedDict

class GoogleDriveCreds(TypedDict, total=False):
    google_drive_tokens: str
    google_drive_service_account_key: str
    primary_admin_email: str  # required

def is_complete_gdrive_creds(d: dict) -> bool:
    return "primary_admin_email" in d and (
        "google_drive_tokens" in d or "google_drive_service_account_key" in d
    )

Try / catch

try:
    connector.load_credentials(raw)
except ValueError as e:
    if "primary admin key" in str(e):
        raw.setdefault("primary_admin_email", ask_admin_email())
        connector.load_credentials(raw)

Prevention

When it happens

Trigger: Passing a credentials dict that was built for another connector type, a hand-written token JSON without the primary_admin_email field, or an export/migration that dropped the key.

Common situations: Users pasting the OAuth token blob (client_id/refresh_token only) directly into the credential field without the surrounding structure the app expects, upgrading between versions where the key name changed, CI scripts writing minimal credentials.

Related errors


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