{"record":{"id":"7bc2815425c396f1","repo":"transloadit/uppy","slug":"received-no-remote-credentials","errorCode":null,"errorMessage":"Received no remote credentials","messagePattern":"Received no remote credentials","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@uppy/companion/src/server/provider/credentials.ts","lineNumber":32,"sourceCode":"/**\n * @param url\n * @param providerName\n * @param credentialRequestParams - null asks for default credentials.\n */\nasync function fetchKeys(\n  url: string,\n  providerName: string,\n  credentialRequestParams: unknown | null,\n) {\n  try {\n    const { credentials } = await got\n      .post(url, {\n        json: { provider: providerName, parameters: credentialRequestParams },\n      })\n      .json<{ credentials?: CredentialsFetchResponse }>()\n\n    if (!isRecord(credentials))\n      throw new Error('Received no remote credentials')\n\n    return credentials\n  } catch (err) {\n    logger.error(err, 'credentials.fetch.fail')\n    throw err\n  }\n}\n\n/**\n * Fetches for a providers OAuth credentials. If the config for that provider allows fetching\n * of the credentials via http, and the `credentialRequestParams` argument is provided, the oauth\n * credentials will be fetched via http. Otherwise, the credentials provided via companion options\n * will be used instead.\n *\n * @param providerName the name of the provider whose oauth keys we want to fetch (e.g onedrive)\n * @param companionOptions the companion options object\n * @param credentialRequestParams the params that should be sent if an http request is required.\n */","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/transloadit/uppy/blob/5d4dedd02a1ac0ae022c75c54aca76558f88e256/packages/@uppy/companion/src/server/provider/credentials.ts#L14-L50","documentation":"When Companion is configured with a credentialsUrl (custom/remote credentials service), it POSTs the provider name and request parameters to that endpoint and expects a JSON credentials object back. If the response body is missing or not a plain object, this error is thrown before the error is logged and re-raised to the caller.","triggerScenarios":"Configuring companionOptions.providerOptions.credentialsUrl (or per-provider custom credentials) to an endpoint that returns an empty body, a JSON array/string instead of an object, a 200 page with HTML (mis-routed endpoint), or one that crashes and returns nothing parseable.","commonSituations":"The credentials microservice is down or mis-deployed, the URL has a typo so a generic 200 catch-all page responds, the endpoint returns { data: {...} } wrapping instead of a top-level object, or auth between Companion and the service silently fails.","solutions":["curl -X POST the credentials endpoint with the same payload and confirm it returns a JSON object with the provider's keys/secrets","Verify the credentialsUrl path, protocol, and any auth headers are correct in Companion config","Make the endpoint return a top-level JSON object (not wrapped in data) with valid status codes","Check the credentials service logs — Companion logs this as credentials.fetch.fail with the underlying error"],"exampleFix":"// before (credentials service)\napp.post('/credentials', (req, res) => res.json({ data: { key: k, secret: s } }))\n\n// after\napp.post('/credentials', (req, res) => res.json({ key: k, secret: s }))","handlingStrategy":"try-catch","validationCode":"// Health-check the credentials service before relying on it\nconst res = await fetch(credentialsUrl, {\n  method: 'POST',\n  headers: { 'content-type': 'application/json' },\n  body: JSON.stringify({ provider: 'drive', parameters: {} }),\n})\nconst json = await res.json().catch(() => null)\nif (!json || typeof json !== 'object') throw new Error('credentials service unhealthy')","typeGuard":"function isCredentialsRecord(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v)\n}","tryCatchPattern":"try {\n  const creds = await companion.getProviderCredentials()\n} catch (err) {\n  if (err instanceof Error && err.message === 'Received no remote credentials') {\n    alertProviderOps('credentials service down')\n  }\n  throw err\n}","preventionTips":["Add monitoring/alerting on credentials.fetch.fail log events","Return proper JSON errors (non-2xx) from the credentials service so got raises status errors instead","Contract-test the credentials service response shape in CI"],"tags":["companion","credentials","provider","configuration"],"backgroundTag":"remote-service-invalid-response","analyzedSha":"5d4dedd02a1ac0ae022c75c54aca76558f88e256","analyzedAt":"2026-08-28T12:18:41.267Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}