1"use strict";(globalThis.webpackChunkcoalesce_docs=globalThis.webpackChunkcoalesce_docs||[]).push([[3948],{23208(e,t,a){a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"catalog/integrations/data-viz/metabase","title":"Metabase","description":"Integrate Metabase into Coalesce Catalog. Choose Catalog-managed Metabase API credentials or client-managed extraction with the API or PostgreSQL application database. Allowlist Catalog IPs and run castor-extractor when you self-host extraction.","source":"@site/docs/catalog/integrations/data-viz/metabase.md","sourceDirName":"catalog/integrations/data-viz","slug":"/catalog/integrations/data-viz/metabase","permalink":"/docs/catalog/integrations/data-viz/metabase","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"title":"Metabase","description":"Integrate Metabase into Coalesce Catalog. Choose Catalog-managed Metabase API credentials or client-managed extraction with the API or PostgreSQL application database. Allowlist Catalog IPs and run castor-extractor when you self-host extraction.","keywords":["Metabase","Catalog","BI integration","castor-extractor","Metabase API","PostgreSQL"],"processed":true},"sidebar":"catalogSidebar","previous":{"title":"Looker Studio","permalink":"/docs/catalog/integrations/data-viz/looker-studio"},"next":{"title":"Omni","permalink":"/docs/catalog/integrations/data-viz/omni"}}');var n=a(74848),o=a(28453);const r={title:"Metabase",description:"Integrate Metabase into Coalesce Catalog. Choose Catalog-managed Metabase API credentials or client-managed extraction with the API or PostgreSQL application database. Allowlist Catalog IPs and run castor-extractor when you self-host extraction.",keywords:["Metabase","Catalog","BI integration","castor-extractor","Metabase API","PostgreSQL"],processed:!0},i=void 0,l={},c=[{value:"Requirements",id:"requirements",level:2},{value:"Metabase API Prerequisites",id:"metabase-api-prerequisites",level:3},{value:"PostgreSQL Application Database Path",id:"postgresql-application-database-path",level:3},{value:"Allowlist Catalog IP",id:"allowlist-catalog-ip",level:2},{value:"Catalog Managed",id:"catalog-managed",level:2},{value:"Client Managed",id:"client-managed",level:2},{value:"Doing a One-Shot Extract",id:"doing-a-one-shot-extract",level:3},{value:"Running the Extraction Package",id:"running-the-extraction-package",level:3},{value:"Install the PyPI Package",id:"install-the-pypi-package",level:4},{value:"Run the Package",id:"run-the-package",level:4},{value:"Credentials",id:"credentials",level:4},{value:"Other Arguments",id:"other-arguments",level:4},{value:"Scheduling and Push to Catalog",id:"scheduling-and-push-to-catalog",level:3},{value:"Arguments",id:"arguments",level:4},{value:"Target Files",id:"target-files",level:4},{value:"Troubleshooting",id:"troubleshooting",level:2},{value:"You Chose the API Path but Ingestion Stays Shallow on Dashboards",id:"you-chose-the-api-path-but-ingestion-stays-shallow-on-dashboards",level:3},{value:"Confusion Between Metabase Application PostgreSQL and Your Warehouse PostgreSQL",id:"confusion-between-metabase-application-postgresql-and-your-warehouse-postgresql",level:3},{value:"Catalog-Managed Credentials Fail Immediately",id:"catalog-managed-credentials-fail-immediately",level:3},{value:"Extractor Logs Stop Mid-Collection",id:"extractor-logs-stop-mid-collection",level:3},{value:"Upload Succeeds but Dashboards Never Refresh",id:"upload-succeeds-but-dashboards-never-refresh",level:3}];function d(e){const t={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",h4:"h4",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.p,{children:"Integrate Metabase into Coalesce Catalog so dashboard and metadata content stays available alongside your warehouse lineage."}),"\n",(0,n.jsx)(t.h2,{id:"requirements",children:"Requirements"}),"\n",(0,n.jsx)(t.admonition,{title:"Warehouse Integration Required",type:"warning",children:(0,n.jsx)(t.p,{children:"A Warehouse type integration must already be configured to complete the first ingestion of this integration."})}),"\n",(0,n.jsxs)(t.p,{children:["Catalog ingests Metabase metadata using one of two technical paths: the ",(0,n.jsx)(t.strong,{children:"Metabase HTTP API"}),", or ",(0,n.jsx)(t.strong,{children:"read-only SQL"})," against the ",(0,n.jsx)(t.strong,{children:"PostgreSQL database Metabase uses as its application database"}),". Metabase stores questions, dashboards, and collections there. That PostgreSQL instance is not your warehouse."]}
1),"\n",(0,n.jsxs)(t.p,{children:["How you connect breaks down along two choices: the ",(0,n.jsx)(t.strong,{children:"connector"})," and whether extraction is ",(0,n.jsx)(t.strong,{children:"Catalog managed"})," or ",(0,n.jsx)(t.strong,{children:"client managed"}),". The connector is either the API or the PostgreSQL application database. ",(0,n.jsx)(t.strong,{children:"Catalog managed"})," means credentials live in the Coalesce App. ",(0,n.jsx)(t.strong,{children:"Client managed"})," means you run the extractor. Use this table to match your setup to the connector:"]}),"\n",(0,n.jsxs)(t.table,{children:[(0,n.jsx)(t.thead,{children:(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.th,{children:"Setup"}),(0,n.jsx)(t.th,{children:"Connector"}),(0,n.jsx)(t.th,{children:"What you use"})]})}),(0,n.jsxs)(t.tbody,{children:[(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{children:"Catalog managed"}),(0,n.jsx)(t.td,{children:"Metabase API"}),(0,n.jsxs)(t.td,{children:["JSON credentials in the Coalesce App. See ",(0,n.jsx)(t.a,{href:"#catalog-managed",children:"Catalog Managed"}),"."]})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{children:"Client managed"}),(0,n.jsx)(t.td,{children:"Metabase API"}),(0,n.jsxs)(t.td,{children:[(0,n.jsx)(t.code,{children:"castor-extract-metabase-api"})," with API credentials. See ",(0,n.jsx)(t.a,{href:"#client-managed",children:"Client Managed"}),"."]})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{children:"Client managed"}),(0,n.jsx)(t.td,{children:"PostgreSQL application database"}),(0,n.jsxs)(t.td,{children:[(0,n.jsx)(t.code,{children:"castor-extract-metabase-db"})," with read-only PostgreSQL credentials for Metabase application tables. See ",(0,n.jsx)(t.a,{href:"#client-managed",children:"Client Managed"}),"."]})]})]})]}),"\n",(0,n.jsx)(t.h3,{id:"metabase-api-prerequisites",children:"Metabase API Prerequisites"}),"\n",(0,n.jsxs)(t.p,{children:["For Catalog managed onboarding or the API extraction script, the Metabase account must meet Metabase privilege requirements for metadata access through the API. The castor-extractor documentation refers to this as the Metabase ",(0,n.jsx)(t.code,{children:"superuser"})," role. That is a permission on the Metabase account, not a requirement tied to a person's job title. For API limitations such as popularity metrics, see ",(0,n.jsx)(t.a,{href:"/docs/catalog/developer/castor-extractor/bi-tools/metabase",children:"Metabase package documentation"}),"."]}),"\n",(0,n.jsx)(t.h3,{id:"postgresql-application-database-path",children:"PostgreSQL Application Database Path"}),"\n",(0,n.jsxs)(t.p,{children:["Read-only access to the PostgreSQL instance Metabase uses for application metadata applies when you run ",(0,n.jsx)(t.strong,{children:"client-managed"})," extraction with ",(0,n.jsx)(t.code,{children:"castor-extract-metabase-db"}),". Catalog managed onboarding does not collect PostgreSQL host or database credentials for Metabase. See ",(0,n.jsx)(t.a,{href:"https://www.metabase.com/docs/latest/operations-guide/configuring-application-database.html#postgres",children:"Metabase configuration documentation"})," for how Metabase configures its application database."]}),"\n",(0,n.jsx)(t.h2,{id:"allowlist-catalog-ip",children:"Allowlist Catalog IP"}),"\n",(0,n.jsx)(t.p,{children:"Here are our fixed IPs:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["For instances on ",(0,n.jsx)(t.a,{href:"https://app.us.castordoc.com/",children:"app.us.castordoc.com"}),": ",(0,n.jsx)(t.code,{children:"34.42.92.72"})]}),"\n",(0,n.jsxs)(t.li,{children:["For instances on ",(0,n.jsx)(t.a,{href:"https://app.castordoc.com/",children:"app.castordoc.com"}),": ",(0,n.jsx)(t.code,{children:"35.246.176.138"})]}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"catalog-managed",children:"Catalog Managed"}),"\n",(0,n.jsx)(t.p,{children:"You can enter your credentials directly in the Coalesce App."}),"\n",(0,n.jsx)(t.p,{children:"Using the API:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-json",children:'{\n "baseUrl": "http://company.cloud.metabase.com",\n "user": "catalog",\n "password": "abcdefgh"\n}\n'})}),"\n",(0,n.jsx)(t.p,{children:"For your first sync, it will take up to 48 hours and we will let you know
1when it is complete."}),"\n",(0,n.jsxs)(t.p,{children:["If you are not comfortable giving us access to your credentials, continue to ",(0,n.jsx)(t.a,{href:"#client-managed",children:"Client Managed"}),"."]}),"\n",(0,n.jsx)(t.h2,{id:"client-managed",children:"Client Managed"}),"\n",(0,n.jsx)(t.h3,{id:"doing-a-one-shot-extract",children:"Doing a One-Shot Extract"}),"\n",(0,n.jsx)(t.p,{children:"For your trial, you can simply give us a one-shot view of your BI tool."}),"\n",(0,n.jsxs)(t.p,{children:["To get things working quickly, here is a ",(0,n.jsx)(t.a,{href:"https://colab.research.google.com/drive/1e6fDexKyLWRykocmQsw6nZ1EpEuGuzis?usp=sharing",children:"Google Colab"})," to run our package swiftly."]}),"\n",(0,n.jsx)(t.h3,{id:"running-the-extraction-package",children:"Running the Extraction Package"}),"\n",(0,n.jsx)(t.h4,{id:"install-the-pypi-package",children:"Install the PyPI Package"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"pip install castor-extractor[metabase]\n"})}),"\n",(0,n.jsxs)(t.p,{children:["For further details, see the ",(0,n.jsx)(t.a,{href:"https://pypi.org/project/castor-extractor/#pip-install",children:"castor-extractor installation instructions"}),"."]}),"\n",(0,n.jsx)(t.h4,{id:"run-the-package",children:"Run the Package"}),"\n",(0,n.jsx)(t.p,{children:"Once the package has been installed, you should be able to run the following command in your terminal:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"castor-extract-metabase-db [arguments]\n\n# or, if you use the API connector:\ncastor-extract-metabase-api [arguments]\n"})}),"\n",(0,n.jsx)(t.p,{children:"The script will run and display logs as follows:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"INFO - Getting session_id: {'id': '****'}\nINFO - Fetching USER (15 results)\nINFO - Wrote output file: /tmp/catalog/1649081473-user.json\nINFO - Fetching COLLECTION (41 results)\n\n...\n\nINFO - Wrote output file: /tmp/catalog/1649081473-dashboard_cards.json\nINFO - Wrote output file: /tmp/catalog/1649081473-summary.json\n"})}),"\n",(0,n.jsx)(t.h4,{id:"credentials",children:"Credentials"}),"\n",(0,n.jsx)(t.p,{children:"You can sign in using one of the following methods:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.strong,{children:"Postgres connector"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-H"}),", ",(0,n.jsx)(t.code,{children:"--host"}),": Host name where the server is running"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-P"}),", ",(0,n.jsx)(t.code,{children:"--port"}),": TCP/IP port number"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-d"}),", ",(0,n.jsx)(t.code,{children:"--database"}),": Database name"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-s"}),", ",(0,n.jsx)(t.code,{children:"--schema"}),": Schema name where the views or tables are located"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-u"}),", ",(0,n.jsx)(t.code,{children:"--user"}),": User"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-p"}),", ",(0,n.jsx)(t.code,{children:"--password"}),": Password"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-o"}),", ",(0,n.jsx)(t.code,{children:"--output"}),": Directory to write to"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"--require_ssl"}),": Flag to require SSL"]}),"\n"]}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.strong,{children:"API connector"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-b"}),", ",(0,n.jsx)(t.code,{children:"--base-url"}),": Metabase base URL, such as ",(0,n.jsx)(t.code,{children:"http://company.cloud.metabase.com"})]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-u"}),", ",(0,n.jsx)(t.code,{children:"--user"}),": Metabase user"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-p"}),", ",(0,n.jsx)(t.code,{children:"--password"}),": Metabase password"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(t.h4,{id:"other-arguments",children:"Other Arguments"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-o"}),", ",(0,n.jsx)(t.code,{children:"--output"}),": target folder to store the extracted files"]}),"\n"]}),"\n",(0,n.jsxs)(t.p,{children:["Run any extractor command with ",(0,n.jsx)(t.code,{children:"--help"})," to list all arguments."]}),"\n",(0,n.jsx)(t.h3,{id:"scheduling-and-push-to-catalog",children:"Scheduling and Push to Catalog"}),"\n",(0,n.jsx)(t.p,{children:"When moving out of trial, you will want to refresh your Metabase content in Catalog. Here is how to do it:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["Your source id from Catalog. In the code examples, this value is called ",(0,n.jsx)(t.code,{children:"source_id"}),"."]}),"\n",(0,n.jsx)(t.li,{children:"Your Catalog Token from the Catalog team"}),"\n"]}),"\n",(0,n.jsx)(t.p,{children:"The Catalog team will provide you with:"}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"Catalog Identifier"}),": An id we use to match your Metabase files with your Catalog instance"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"Catalog Token"}),": An API token"]}),"\n"]}),"\n",(0,n.jsxs)(t.p,{children:["You can then use the ",(0,n.jsx)(t.code,{children:"castor-upload"})," command:"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"castor-upload [arguments]\n"})}),"\n",(0,n.jsx)(t.h4,{id:"arguments",children:"Arguments"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-k"}),", ",(0,n.jsx)(t.code,{children:"--token"}),": Token provided by Catalog"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-s"}),", ",(0,n.jsx)(t.code,{children:"--source_id"}),": account id provided by Catalog"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-t"}),", ",(0,n.jsx)(t.code,{children:"--file_type"}),": source type to upload. Currently supported are ",(0,n.jsx)(t.code,{children:"DBT"}),", ",(0,n.jsx)(t.code,{children:"VIZ"}),", or ",(0,n.jsx)(t.code,{children:"WAREHOUSE"})]}),"\n"]}),"\n",(0,n.jsx)(t.h4,{id:"target-files",children:"Target Files"}),"\n",(0,n.jsxs)(t.p,{children:["To specify the target files, provide ",(0,n.jsx)(t.strong,{children:"one"})," of the following:"]}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-f"}),", ",(0,n.jsx)(t.code,{children:"--file_path"}),": to push a single file"]}),"\n"]}),"\n",(0,n.jsx)(t.p,{children:"or"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"-d"}),", ",(0,n.jsx)(t.code,{children:"--directory_path"}),": to push several files at once"]}),"\n"]}),"\n",(0,n.jsxs)(t.admonition,{title:"Directory Contents",type:"warning",children:[(0,n.jsxs)(t.p,{children:["The tool will upload ",(0,n.jsx)(t.strong,{children:"all files"})," included in the given directory."]}),(0,n.jsx)(t.p,{children:"Make sure it contains only the extracted files before pushing."})]}
1),"\n",(0,n.jsx)(t.p,{children:"Then you will have to schedule the script run and the push to Catalog. Use your preferred scheduler to create this job."}),"\n",(0,n.jsx)(t.p,{children:"After you schedule the extractor runs and uploads, Metabase content stays current in Catalog."}),"\n",(0,n.jsx)(t.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,n.jsx)(t.p,{children:"These checks cover both Catalog-managed Metabase onboarding and client-managed extractors."}),"\n",(0,n.jsx)(t.h3,{id:"you-chose-the-api-path-but-ingestion-stays-shallow-on-dashboards",children:"You Chose the API Path but Ingestion Stays Shallow on Dashboards"}),"\n",(0,n.jsxs)(t.p,{children:["Metabase labels certain accounts as ",(0,n.jsx)(t.strong,{children:"superuser"})," for API access in extractor documentation. Without that privilege tier, popular metrics and some collections may not export."]}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.strong,{children:"Resolution:"})}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:["Confirm the Metabase account tied to Catalog meets the API prerequisites in ",(0,n.jsx)(t.a,{href:"/docs/catalog/developer/castor-extractor/bi-tools/metabase",children:"Metabase package documentation"}),"."]}),"\n",(0,n.jsx)(t.li,{children:"Retry ingestion after promoting the account or switching to an administrative service account permitted by your Metabase policy."}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"confusion-between-metabase-application-postgresql-and-your-warehouse-postgresql",children:"Confusion Between Metabase Application PostgreSQL and Your Warehouse PostgreSQL"}),"\n",(0,n.jsxs)(t.p,{children:["Catalog never asks for your warehouse credentials when you pick ",(0,n.jsx)(t.strong,{children:"Catalog managed"})," onboarding for Metabase. Client-managed extraction with ",(0,n.jsx)(t.code,{children:"castor-extract-metabase-db"})," connects to the PostgreSQL database Metabase itself uses for app metadata, not your analytical warehouse."]}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.strong,{children:"Resolution:"})}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:["Point ",(0,n.jsx)(t.code,{children:"--host"})," and ",(0,n.jsx)(t.code,{children:"--database"})," at Metabase's application database host from Metabase admin settings."]}),"\n",(0,n.jsx)(t.li,{children:"Keep read-only accounts limited to Metabase metadata tables only."}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"catalog-managed-credentials-fail-immediately",children:"Catalog-Managed Credentials Fail Immediately"}),"\n",(0,n.jsx)(t.p,{children:"Incorrect base URL format or blocked outbound traffic stops login before extraction begins."}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.strong,{children:"Resolution:"})}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:["Allowlist Catalog IPs from ",(0,n.jsx)(t.strong,{children:"Allowlist Catalog IP"})," on this page when Metabase sits behind a firewall."]}),"\n",(0,n.jsxs)(t.li,{children:["Validate JSON keys such as ",(0,n.jsx)(t.code,{children:"baseUrl"}),", ",(0,n.jsx)(t.code,{children:"user"}),", and ",(0,n.jsx)(t.code,{children:"password"})," against Metabase's HTTPS endpoint."]}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"extractor-logs-stop-mid-collection",children:"Extractor Logs Stop Mid-Collection"}),"\n",(0,n.jsx)(t.p,{children:"Large Metabase instances sometimes hit API rate limits or disk limits on the runner."}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.strong,{children:"Resolution:"})}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:["Re-run with a larger output directory (",(0,n.jsx)(t.code,{children:"-o"}),") on the extractor host."]}),"\n",(0,n.jsx)(t.li,{children:"Split collections by scheduling incremental pushes instead of one oversized upload directory."}),"\n"]}),"\n",(0,n.jsx)(t.h3,{id:"upload-succeeds-but-dashboards-never-refresh",children:"Upload Succeeds but Dashboards Never Refresh"}),"\n",(0,n.jsxs)(t.p,{children:["Schedulers often point to stale directories or wrong ",(0,n.jsx)(t.code,{children:"source_id"}),"."]}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.strong,{children:"Resolution:"})}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:["Confirm ",(0,n.jsx)(t.code,{children:"castor-upload"})," receives the current ",(0,n.jsx)(t.code,{children:"source_id"})," from Catalog operations."]}),"\n",(0,n.jsxs)(t.li,{children:["Verify cron jobs replace ",(0,n.jsx)(t.strong,{children:"all"}
1)," JSON outputs between runs so partial uploads do not leave mixed timestamps."]}),"\n"]}),"\n",(0,n.jsx)(t.hr,{})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},28453(e,t,a){a.d(t,{R:()=>r,x:()=>i});var s=a(96540);const n={},o=s.createContext(n);function r(e){const t=s.useContext(o);return s.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:r(e.components),s.createElement(o.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.