{"record":{"id":"b475b6b8b5331f21","repo":"transloadit/uppy","slug":"upload-destination-does-not-match-any-allowed-dest","errorCode":null,"errorMessage":"upload destination does not match any allowed destinations","messagePattern":"upload destination does not match any allowed destinations","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"packages/@uppy/companion/src/server/Uploader.ts","lineNumber":165,"sourceCode":"\n  // s3 uploads don't require upload destination\n  // validation, because the destination is determined\n  // by the server's s3 config\n  if (options.protocol !== PROTOCOLS.s3Multipart) {\n    if (!options.endpoint && !options.uploadUrl) {\n      throw new ValidationError('no destination specified')\n    }\n\n    const validateUrl = (url: string | undefined): void => {\n      if (url == null) return\n      const validatorOpts = { require_protocol: true, require_tld: false }\n      if (!validator.isURL(url, validatorOpts)) {\n        throw new ValidationError('invalid destination url')\n      }\n\n      const allowedUrls = options.companionOptions.uploadUrls\n      if (allowedUrls && !hasMatch(url, allowedUrls)) {\n        throw new ValidationError(\n          'upload destination does not match any allowed destinations',\n        )\n      }\n    }\n\n    ;[options.endpoint, options.uploadUrl].forEach(validateUrl)\n  }\n\n  if (options.chunkSize != null && typeof options.chunkSize !== 'number') {\n    throw new ValidationError('incorrect chunkSize')\n  }\n}\n\nconst states = {\n  idle: 'idle',\n  uploading: 'uploading',\n  paused: 'paused',\n  done: 'done',","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/transloadit/uppy/blob/5d4dedd02a1ac0ae022c75c54aca76558f88e256/packages/@uppy/companion/src/server/Uploader.ts#L147-L183","documentation":"When the Companion server is configured with companionOptions.uploadUrls (an allowlist of permitted upload destinations), every supplied endpoint/uploadUrl must match at least one entry (via hasMatch). A well-formed but non-allowlisted URL triggers this ValidationError.","triggerScenarios":"Companion started with UPLOAD_URLS='[\"https://allowed.example.com/upload\"]' while the client sends endpoint 'https://other.example.com/upload'; or a glob pattern in uploadUrls that doesn't cover the subdomain/path used.","commonSituations":"Adding an upload allowlist for security and forgetting to include the client's actual destination; env var formatting mistakes (JSON string vs array); changing the client destination without updating the server allowlist.","solutions":["Add the client's exact destination URL to Companion's uploadUrls option (comma-separated via the UPLOAD_URLS env var)","Check for trailing slashes, port numbers, or subdomain mismatches between the allowlist entry and the sent URL","Redeploy/restart Companion after changing the allowlist so options are re-read"],"exampleFix":"# before\nUPLOAD_URLS='[\"https://allowed.example.com/upload\"]'\n\n# after (client posts to https://uploads.allowed.example.com/upload)\nUPLOAD_URLS='[\"https://allowed.example.com/upload\", \"https://uploads.allowed.example.com/upload\"]'","handlingStrategy":"validation","validationCode":"const ALLOWED = ['https://allowed.example.com/upload'] // mirror server UPLOAD_URLS\nconst ok = (u: string) => ALLOWED.some((a) => u.startsWith(a))\nif (!ok(endpoint)) throw new Error('endpoint not in server allowlist')","typeGuard":null,"tryCatchPattern":"try { await uploader.upload() } catch (err) {\n  if (err.message.includes('does not match any allowed destinations')) { /* update allowlist or endpoint */ }\n}","preventionTips":["Keep the client endpoint and server UPLOAD_URLS list in one config source","Add integration tests that assert the configured endpoint passes the allowlist"],"tags":["companion","allowlist","security","uploader"],"backgroundTag":"url-not-in-allowlist","analyzedSha":"5d4dedd02a1ac0ae022c75c54aca76558f88e256","analyzedAt":"2026-08-28T12:18:41.267Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}