{"record":{"id":"de60d17d6d0802d7","repo":"infiniflow/ragflow","slug":"main-returned-a-non-json-serializable-value-de60d1","errorCode":null,"errorMessage":"main() returned a non-JSON-serializable value.","messagePattern":"main\\(\\) returned a non-JSON-serializable value\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"internal/agent/sandbox/result_protocol.go","lineNumber":117,"sourceCode":"\t// template-literal escapes only on the JS side. We pass them\n\t// through as-is.\n\treturn code + `\n\nconst __ragflowArgsB64 = \"` + argsB64 + `\";\nconst __ragflowArgs = JSON.parse(Buffer.from(__ragflowArgsB64, 'base64').toString('utf8'));\n\n(async () => {\n  const __ragflowMain = typeof main !== 'undefined' ? main : module.exports && module.exports.main;\n  if (typeof __ragflowMain !== 'function') {\n    throw new Error('main() must be defined or exported.');\n  }\n  const output = await Promise.resolve(__ragflowMain(__ragflowArgs));\n  if (typeof output === 'undefined') {\n    throw new Error('main() must return a value. Use null for an empty result.');\n  }\n  const payload = JSON.stringify({ present: true, value: output, type: 'json' });\n  if (typeof payload === 'undefined') {\n    throw new Error('main() returned a non-JSON-serializable value.');\n  }\n  console.log('` + resultMarkerPrefix + `' + Buffer.from(payload, 'utf8').toString('base64'));\n})();\n`\n}\n\n// ExtractStructuredResult scans stdout for the marker line, decodes\n// the JSON payload after it, and returns the user-visible stdout\n// (with the marker line removed) plus the parsed structured result.\n//\n// The Python side returns `(cleaned_stdout, structured_result_dict)`.\n// On Go the dict is `map[string]any`.\n//\n// Edge cases (matching the Python implementation):\n//   - empty stdout → (\"\", empty map).\n//   - multiple marker lines → only the LAST one wins (later result\n//     overrides earlier). The Python implementation does the same\n//     because the loop overwrites `structured_result`.","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/internal/agent/sandbox/result_protocol.go#L99-L135","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","Use the UI's credential flow rather than hand-crafting JSON so the key is populated","If migrating, re-run the credential creation step instead of copying partial payloads"],"exampleFix":"# before\ncredentials = {\"google_drive_tokens\": {\"refresh_token\": \"...\"}}\nconnector.load_credentials(credentials)  # ValueError\n\n# after\ncredentials = {\n    \"google_drive_tokens\": {\"refresh_token\": \"...\"},\n    \"primary_admin_email\": \"admin@acme.com\",\n}\nconnector.load_credentials(credentials)","handlingStrategy":"validation","validationCode":"PRIMARY_ADMIN_KEY = \"primary_admin_email\"  # DB_CREDENTIALS_PRIMARY_ADMIN_KEY\n\ndef credential_has_admin_key(creds: dict) -> bool:\n    return PRIMARY_ADMIN_KEY in creds and \"@\" in str(creds[PRIMARY_ADMIN_KEY])","typeGuard":"from typing import TypedDict\n\nclass GoogleDriveCreds(TypedDict, total=False):\n    google_drive_tokens: str\n    google_drive_service_account_key: str\n    primary_admin_email: str  # required\n\ndef is_complete_gdrive_creds(d: dict) -> bool:\n    return \"primary_admin_email\" in d and (\n        \"google_drive_tokens\" in d or \"google_drive_service_account_key\" in d\n    )","tryCatchPattern":"try:\n    connector.load_credentials(raw)\nexcept ValueError as e:\n    if \"primary admin key\" in str(e):\n        raw.setdefault(\"primary_admin_email\", ask_admin_email())\n        connector.load_credentials(raw)","preventionTips":["Use the app's credential UI, which injects the admin key automatically","When scripting, template the credential JSON with the admin key pre-filled","Validate shape with is_complete_gdrive_creds() before persisting"],"tags":["google-drive","credentials","validation","configuration"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}