{"record":{"id":"e17c2005113855e2","repo":"infiniflow/ragflow","slug":"failed-to-fetch-memory-detail","errorCode":null,"errorMessage":"Failed to fetch memory detail","messagePattern":"Failed to fetch memory detail","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/pages/memories/hooks.ts","lineNumber":151,"sourceCode":"    id: memoryId,\n  };\n  if (shared_id) {\n    param = {\n      id: memoryId,\n      tenant_id: tenantId,\n    };\n  }\n  const fetchMemoryDetailFunc = shared_id\n    ? memoryService.getMemoryDetailShare\n    : memoryService.getMemoryDetail;\n\n  const { data, isLoading, isError } = useQuery<MemoryDetailResponse, Error>({\n    queryKey: ['memoryDetail', memoryId],\n    enabled: !shared_id || !!tenantId,\n    queryFn: async () => {\n      const { data: response } = await fetchMemoryDetailFunc(param);\n      if (response.code !== 0) {\n        throw new Error(response.message || 'Failed to fetch memory detail');\n      }\n      return response;\n    },\n  });\n\n  return { data: data?.data, isLoading, isError };\n};\n\nexport const useDeleteMemory = () => {\n  const { t } = useTranslation();\n  const queryClient = useQueryClient();\n  const {\n    data,\n    isError,\n    mutateAsync: deleteMemoryMutation,\n  } = useMutation<DeleteMemoryResponse, Error, DeleteMemoryProps>({\n    mutationKey: ['deleteMemory'],\n    mutationFn: async (props) => {","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/web/src/pages/memories/hooks.ts#L133-L169","documentation":"In get_google_creds, when the stored token JSON lacks client_id/client_secret/refresh_token the code tries ensure_oauth_token_dict to regenerate tokens from a client secret; when that also fails (no usable client config, flow error) a PermissionError is raised telling the user to finish the OAuth flow.","triggerScenarios":"Credential dict contains a token blob with only an access token or only a client_secret.json-style fragment without 'installed'/'web' keys; or ensure_oauth_token_dict raises because the interactive flow cannot run in a headless server process.","commonSituations":"Pasting a client_secret.json downloaded from GCP directly into the token field (no 'installed' wrapper key), partial manual token edits, running the connector in a container where the local-server OAuth flow cannot open a browser.","solutions":["Run the standalone OAuth flow (scripts/google_oauth_flow or equivalent) to mint a complete {client_id, client_secret, refresh_token} blob and paste that as the credential","If providing only a client config, structure it as {'installed': {...}} or {'web': {...}} so ensure_oauth_token_dict can drive the flow","Never hand-trim fields out of a working token JSON"],"exampleFix":"# before: pasted client_secret.json\n{ \"installed\": {\"client_id\": \"...\", \"client_secret\": \"...\"} }\n# with fields flattened away → incomplete token dict\n\n# after: complete token blob from a finished flow\n{ \"client_id\": \"...\", \"client_secret\": \"...\",\n  \"refresh_token\": \"1//0e...\", \"token_uri\": \"...\" }","handlingStrategy":"validation","validationCode":"def is_complete_oauth_blob(d: dict) -> bool:\n    return all(k in d for k in (\"client_id\", \"client_secret\", \"refresh_token\"))\n\ndef oauth_blob_or_runnable_flow(d: dict) -> bool:\n    return is_complete_oauth_blob(d) or \"installed\" in d or \"web\" in d","typeGuard":"def has_installed_client_config(d: dict) -> bool:\n    return isinstance(d.get(\"installed\"), dict) or isinstance(d.get(\"web\"), dict)","tryCatchPattern":"try:\n    creds, new_dict = get_google_creds(credentials, source)\nexcept PermissionError as e:\n    if \"finish the OAuth flow\" in str(e):\n        credentials[\"google_drive_tokens\"] = json.dumps(run_oauth_flow_headless_safe())\n        creds, new_dict = get_google_creds(credentials, source)","preventionTips":["Generate tokens once in a browser-capable environment and reuse the blob","Never run the interactive flow from long-lived server processes; pre-mint instead","Script a shape check (is_complete_oauth_blob) at credential-save time"],"tags":["google-drive","oauth","credentials","configuration"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}