Skip to content

Codec server "could not connect" — new URL(type, endpoint) drops endpoint's last path segment (regression from #3345) #3399

@ryanfreckleton

Description

@ryanfreckleton

Describe the bug

Since #3345 merged on 2026-05-15, codec server requests fail to reach the configured endpoint when the endpoint URL has path segments and no trailing slash.

The new code in src/lib/services/data-encoder.ts:

const url = new URL(type, endpoint);
url.searchParams.set('preserveStorageRefs', 'true');

…relies on URL resolution, which treats the last path segment of endpoint as a "filename" and discards it. The previous code (endpoint + `/${type}` ) did not have this behavior. v2.47.0 (last tagged) is fine; the regression only affects deployments tracking main, including cloud.temporal.io.

Result: a configured endpoint of https://example.com/v1/api/codec is requested as https://example.com/v1/api/decode, returning 404 (no CORS headers), surfaced in the UI as "Codec Server could not connect."

Verified in the production cloud.temporal.io bundle today — the chunk containing preserveStorageRefs uses the new URL(...) form. Same browser, four URL-resolution variants:

endpoint new URL('decode', endpoint)
https://example.com/v1/api/codec https://example.com/v1/api/decode
https://example.com/v1/api/codec/ https://example.com/v1/api/codec/decode
https://example.com/v1/api/codec/x https://example.com/v1/api/codec/decode
(old) endpoint + '/' + 'decode' https://example.com/v1/api/codec/decode

To Reproduce

  1. Run a codec server with /decode and /encode mounted under a non-root path, e.g. https://example.com/v1/api/codec/decode.
  2. In Temporal Cloud → Settings → Codec Server, set the endpoint to https://example.com/v1/api/codec (no trailing slash). The settings page strips any trailing slash you add, so this is the only saveable form.
  3. Open any encrypted workflow.

Expected behavior

The UI requests https://example.com/v1/api/codec/decode and decodes payloads (behavior in v2.47.0 and earlier).

Actual behavior

The UI requests https://example.com/v1/api/decode → 404 → CORS preflight failure → "Codec Server could not connect" banner.

Desktop

  • OS: macOS 15
  • Browser: Chrome 148, Brave 1.x (Chromium 148)
  • Temporal Cloud UI: production cloud.temporal.io, build post-2.47.0 (bundle contains preserveStorageRefs from DT-3751 - download external payloads #3345).

Additional context

Workaround for users today: configure the endpoint with a meaningless trailing segment, e.g. https://example.com/v1/api/codec/x. new URL('decode', '…/codec/x') resolves to …/codec/decode correctly. This isn't discoverable and is a temporary hack.

Suggested fix — either preserve the previous semantics with string concat:

const url = new URL(`${endpoint.replace(/\/$/, '')}/${type}`);
url.searchParams.set('preserveStorageRefs', 'true');

…or normalize to a trailing slash before resolving:

const base = endpoint.endsWith('/') ? endpoint : endpoint + '/';
const url = new URL(type, base);
url.searchParams.set('preserveStorageRefs', 'true');

The first form is closer to the docs' mental model ("endpoint + /decode") and to the v2.47.0 behavior. Either fix should also be applied to wherever the namespace-settings page (and the per-browser codec popover) strips trailing slashes on save — if those didn't strip the slash, the bug would have a self-service workaround.

cc @rossedfort (author of #3345).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions