coder/code-server · error · Error
Failed to resolve external URI: ${uri.toString()}. Could not
Error message
Failed to resolve external URI: ${uri.toString()}. Could not determine base url because productConfiguration missing. What it means
Thrown by the resolveExternalUri implementation added in proxy-uri.diff when the URI to resolve is a localhost URI on a different authority than location.host AND config.productConfiguration or config.productConfiguration.proxyEndpointTemplate is missing. Without the template the code cannot construct the proxied URL for the external port, so it aborts rather than silently returning a broken link.
Source
Thrown at patches/proxy-uri.diff:121
+import { extractLocalHostUriMetaDataForPortMapping, TunnelOptions, TunnelCreationOptions } from '../../../platform/tunnel/common/tunnel.js';
import type { IURLCallbackProvider } from '../../../workbench/services/url/browser/urlService.js';
import { create } from '../../../workbench/workbench.web.main.internal.js';
@@ -612,6 +613,39 @@ class WorkspaceProvider implements IWork
settingsSyncOptions: config.settingsSyncOptions ? { enabled: config.settingsSyncOptions.enabled, } : undefined,
workspaceProvider: WorkspaceProvider.create(config),
urlCallbackProvider: new LocalStorageURLCallbackProvider(config.callbackRoute),
+ resolveExternalUri: (uri: URI): Promise<URI> => {
+ let resolvedUri = uri
+ const localhostMatch = extractLocalHostUriMetaDataForPortMapping(resolvedUri)
+ if (localhostMatch && resolvedUri.authority !== location.host) {
+ if (config.productConfiguration && config.productConfiguration.proxyEndpointTemplate) {
+ const renderedTemplate = config.productConfiguration.proxyEndpointTemplate
+ .replace('{{port}}', localhostMatch.port.toString())
+ .replace('{{host}}', window.location.host)
+ resolvedUri = URI.parse(new URL(renderedTemplate, window.location.href).toString())
+ } else {
+ throw new Error(`Failed to resolve external URI: ${uri.toString()}. Could not determine base url because productConfiguration missing.`)
+ }
+ }
+ // If not localhost, return unmodified.
+ return Promise.resolve(resolvedUri)
+ },
+ tunnelProvider: {
+ tunnelFactory: (tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions) => {
+ const onDidDispose: Emitter<void> = new Emitter();
+ let isDisposed = false;
+ return Promise.resolve({
+ remoteAddress: tunnelOptions.remoteAddress,
+ localAddress: `localhost:${tunnelOptions.remoteAddress.port}`,
+ onDidDispose: onDidDispose.event,
+ dispose: () => {
+ if (!isDisposed) {
+ isDisposed = true;
+ onDidDispose.fire();
+ }View on GitHub (pinned to 51f90a376b)
Solutions
- Provide productConfiguration.proxyEndpointTemplate in the workbench config (e.g. a template like '/proxy/{{port}}/{{host}}').
- Ensure code-server's build injects the product configuration including the proxy endpoint template into the browser.
- If port proxying is disabled, prevent extensions from calling resolveExternalUri for localhost ports (disable forwarded-port open behavior).
- Verify the template contains both {{port}} and {{host}} placeholders.
Example fix
// In the workbench construction options sent to the browser:
config.productConfiguration = {
...config.productConfiguration,
proxyEndpointTemplate: '/proxy/{{port}}/{{host}}',
} Defensive patterns
Strategy: validation
Validate before calling
// Ensure the proxy template is present before resolveExternalUri is reachable.
if (!config.productConfiguration?.proxyEndpointTemplate) {
throw new Error('proxyEndpointTemplate must be configured for port proxying')
} Type guard
function hasProxyTemplate(c: any): boolean {
return !!c?.productConfiguration?.proxyEndpointTemplate
&& c.productConfiguration.proxyEndpointTemplate.includes('{{port}}')
} Try / catch
try {
return await resolveExternalUri(uri)
} catch (e) {
if (/productConfiguration missing/.test(e.message)) return uri // fall back to unmodified URI
} Prevention
- Inject productConfiguration.proxyEndpointTemplate into the browser config.
- Include both {{port}} and {{host}} placeholders in the template.
- If proxying is disabled, also disable extension behaviors that call resolveExternalUri for localhost.
- Keep the product configuration payload in sync with the workbench version.
When it happens
Trigger: An extension or workbench feature calls resolveExternalUri on a localhost:<port> URI whose authority differs from the current page host (a port-forwarding scenario), but the product configuration shipped to the browser lacks proxyEndpointTemplate. This is the typical 'open a forwarded port in browser' path.
Common situations: Running a fork/build that does not inject productConfiguration.proxyEndpointTemplate into the browser config; disabling the proxy feature while extensions still try to resolve localhost URIs; a version mismatch where the template key was renamed.
Related errors
AI-assisted analysis of coder/code-server@51f90a376b (2026-08-12).
Data as JSON: /api/errors/36e47054251f73fd.
Report an issue: GitHub.