{"record":{"id":"7fcbba32fd8cd4d0","repo":"Significant-Gravitas/AutoGPT","slug":"failed-to-fetch-artifact","errorCode":null,"errorMessage":"Failed to fetch artifact","messagePattern":"Failed to fetch artifact","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"autogpt_platform/frontend/src/app/(platform)/copilot/components/ArtifactPanel/components/useArtifactContent.ts","lineNumber":117,"sourceCode":"      if (\n        !isTransientArtifactFetchStatus(response.status) ||\n        attempt === CONTENT_FETCH_MAX_RETRIES\n      ) {\n        throw new ArtifactFetchError(await parseArtifactFetchError(response));\n      }\n    } catch (error) {\n      if (error instanceof ArtifactFetchError) throw error;\n      if (attempt === CONTENT_FETCH_MAX_RETRIES) {\n        throw error instanceof Error\n          ? error\n          : new Error(\"Failed to fetch artifact\");\n      }\n    }\n\n    await sleep(CONTENT_FETCH_RETRY_DELAY_MS);\n  }\n\n  throw new Error(\"Failed to fetch artifact\");\n}\n\nexport function getCachedArtifactContent(id: string): string | undefined {\n  return contentCache.get(id);\n}\n\nexport function clearContentCache() {\n  contentCache.clear();\n}\n\nexport function useArtifactContent(\n  artifact: ArtifactRef,\n  classification: ArtifactClassification,\n) {\n  const [content, setContent] = useState<string | null>(null);\n  const [pdfUrl, setPdfUrl] = useState<string | null>(null);\n  const [isLoading, setIsLoading] = useState(false);\n  const [error, setError] = useState<string | null>(null);","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/frontend/src/app/(platform)/copilot/components/ArtifactPanel/components/useArtifactContent.ts#L99-L135","documentation":"ValueError raised inside _validate_resource_ownership when the StoreListing exists but its owningOrgId differs from the claimed source org. Only the listing's owning org may transfer it; this blocks creating transfers for listings owned by other organizations.","triggerScenarios":"Creating a StoreListing transfer where the caller's active org is not the listing's owningOrgId — wrong org selected, or attempting to transfer a listing the org does not own.","commonSituations":"Multi-org user with the wrong active org; listings visible in the store but owned by a different org; probing another org's listing id.","solutions":["Confirm listing.owningOrgId equals the active org before submitting the transfer.","Restrict transferable listings in the UI to those owned by the active org.","Prompt an org switch when the user belongs to the owning org."],"exampleFix":"# before\nawait create_transfer(\"StoreListing\", lid, source_org=active_org, ...)\n\n# after\nl = await get_store_listing(lid)\nif l.owning_org_id != active_org:\n    raise PermissionError(\"Listing not owned by active org\")\nawait create_transfer(\"StoreListing\", lid, source_org=active_org, ...)","handlingStrategy":"type-guard","validationCode":"l = await get_store_listing(resource_id)\nif l.owning_org_id != active_org_id:\n    raise PermissionError(\"Listing not owned by active org\")","typeGuard":"def listing_owned_by_org(l: StoreListingResponse, org_id: str) -> bool:\n    return l.owning_org_id == org_id","tryCatchPattern":"try:\n    await create_transfer(\"StoreListing\", lid, ...)\nexcept ValueError as e:\n    if \"does not belong\" in str(e):\n        prompt_org_switch()\n    else:\n        raise","preventionTips":["Only offer transfers for listings whose owningOrgId matches the active org","Keep active-org context fresh when browsing store listings"],"tags":["transfers","ownership","store-listing"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}