Skip to content

Add Spectrum troubleshooting docs for top support case drivers#30683

Open
stechedo wants to merge 8 commits into
cloudflare:productionfrom
stechedo:spectrum-troubleshooting-docs
Open

Add Spectrum troubleshooting docs for top support case drivers#30683
stechedo wants to merge 8 commits into
cloudflare:productionfrom
stechedo:spectrum-troubleshooting-docs

Conversation

@stechedo

@stechedo stechedo commented May 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a new Spectrum Troubleshooting page and improves existing Spectrum documentation to address the top 3 case-generating issues identified in the April 2026 Network Support-by-Request (SBR) case review (~190 cases analyzed).

Estimated case deflection: 9-13 cases/month across these 3 issues.

Changes

New page

  • /spectrum/reference/troubleshooting/ — New troubleshooting page with structured symptom/cause/solution sections covering:
    • Health checks failing when IP Access Rules are enabled
    • DNS record conflict when creating Spectrum apps (same hostname as proxied record)
    • Protocol mismatch (origin receives HTTP instead of HTTPS)
    • Error 525 (SSL handshake failed) in Spectrum context
    • Common Spectrum event log status code patterns (444, 445, 497-499, 521, 522)

Modified pages (5)

  • /spectrum/reference/configuration-options/ — Added warnings about IP Access Rules blocking health checks, Custom Rules not working with Spectrum, protocol upgrade not being supported, and double-proxy chains causing 525 errors. Expanded intro paragraph to clarify Spectrum's L4 pass-through behavior.
  • /spectrum/reference/limitations/ — Added new "IP access control" section and "Using the same hostname for HTTP proxy and Spectrum" section documenting the platform limitation and recommending split-hostname architecture (with Citrix Gateway use case).
  • /spectrum/reference/logs/ — Added note clarifying that Spectrum status codes are distinct from HTTP status codes, with cross-link to troubleshooting page.
  • /load-balancing/additional-options/spectrum/ — Added caution callout in the Monitors setup step warning about IP Access Rules blocking health checks.
  • /dns/manage-dns-records/troubleshooting/records-with-same-name/ — Added note explaining that DNS record conflicts also apply to Spectrum applications, with cross-link to Spectrum limitations.

Motivation

These documentation gaps were identified by reviewing all April 2026 Network SBR cases. The top case-generating patterns were:

  1. IP Access Rules + Healthchecks (~3-5 cases/month): Customers enable IP Access Rules, health checks fail silently. No docs explain the interaction.
  2. Same Hostname WAF + Spectrum (~3-4 cases/month): Customers hit "DNS record already exists" error with no explanation that it's a hard platform limitation. Common in Citrix/VDI deployments.
  3. Protocol Mismatch / TLS errors (~3-4 cases/month): Customers expect Spectrum to upgrade HTTP→HTTPS or chain through another Cloudflare proxy. Neither is supported but neither was documented.

Content area

Spectrum, Load Balancing, DNS

@stechedo
stechedo requested a review from dcpena as a code owner May 7, 2026 16:58
@stechedo
stechedo requested a review from a team May 7, 2026 16:58
@stechedo
stechedo requested a review from RebeccaTamachiro as a code owner May 7, 2026 16:58
@github-actions github-actions Bot added product:load-balancing Related to Load Balancing product product:spectrum Related to Spectrum product product:dns Issues or PRs related to DNS product:network size/m labels May 7, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Hey there, we've marked this pull request as stale because there's no recent activity on it. This label helps us identify PRs that might need updates (or to be closed out by our team if no longer relevant).

@cloudflare-docs-bot

cloudflare-docs-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review

⚠️ 12 warnings, 💡 3 suggestions found in commit effc1d7.

Fix in your agent
Fix the following review findings in PR #30683 (https://github.com/cloudflare/cloudflare-docs/pull/30683).

Before making changes, review each finding and present a brief summary table:
- For each finding, state whether you agree, disagree, or need clarification
- If you disagree (e.g. the fix requires disproportionate effort for minimal benefit,
  or the finding is factually incorrect), explain why
- If you need clarification before deciding, ask those questions
- Then share your plan for which issues to tackle and in what order

After triaging, fix all legitimate findings. For any you decide to skip,
post a comment on this PR with the finding ID and your reasoning.

---

## Code Review

### Warnings (11)

#### CR-4050399fb6c0 · Misleading cross-reference
- **File:** `src/content/docs/spectrum/reference/troubleshooting.mdx` line 63
- **Issue:** Line 63 promises more details about the DNS-record conflict limitation and links to `/spectrum/reference/limitations/`, but the Limitations page does not mention this restriction.
- **Fix:** Either add the DNS-record conflict limitation to `src/content/docs/spectrum/reference/limitations.mdx` or remove the promise of more details and point the link elsewhere.

#### CR-9746e1fd141a · Unguarded custom element registration
- **File:** `src/components/AiSearchIndexingDiagram.astro` line 889
- **Issue:** `customElements.define("cfdocs-ai-search-indexing-diagram", ...)` is called unconditionally. If the script is evaluated more than once (e.g., during HMR, in tests, or if the script is otherwise duplicated), the custom element registry throws `NotSupportedError`.
- **Fix:** Make the registration idempotent: `if (!customElements.get("cfdocs-ai-search-indexing-diagram")) { customElements.define(...); }`.

#### CR-b72d87deb669 · Detached element timer leak
- **File:** `src/components/AiSearchQueryingDiagram.astro` line 789
- **Issue:** `disconnectedCallback()` only clears the single pending `this.timer`. A timeout callback that is already queued can still run after the element is removed, call `advance()`, and schedule new timers against a detached DOM tree.
- **Fix:** Guard `advance()` (and the initial `play()` callback) with a `this.isConnected` check, or clear/reset timers when disconnected and avoid scheduling further work.

#### CR-a65044b3f463 · Resource leak on failure path
- **File:** `.flue/workflows/finalize-review.ts` line 146
- **Issue:** When stream results are missing, cleanupPending is awaited then the function returns. But the agent session (created later) is irrelevant here. However, early returns after step 1 (e.g., context missing at line 101, stream missing at 147, PR fetch failed at 177, head moved at 191) leave no created session. The only real resource is the R2 bucket reads. Not a concern.

However, when reconcileStream throws and we catch at lines 332-350, the function continues. That's intended degradation. Not a finding.

Main concern: in step 8, markAutoReviewCompleted failure is caught and logged, but finalize continues and reports success. This silently leaves the auto-review slot unconsumed, which could cause the user to be re-billed/re-reviewed unexpectedly. This is error swallowing but explicitly logged as a non-fatal operation. Could be a warning.

Also: line 438 `await session.delete().catch(() => {});` swallows session deletion errors silently, but that's minor.

More significant: `parsePayload` does not validate `number > 0`, `headSha` nonempty, `dispatchId` nonempty. However that's standard weak validation. Could be a suggestion.

Most concrete issue: Late resource cleanup. When `init(agent)` at line 287 creates a harness/session and any later early return (after session creation) would leave the session active. Looking at code, after line 291 there are no early returns possible, except reconciler degradation which doesn't return. Actually there are no early returns after session creation. So OK.

Wait - line 101 context missing returns before session creation. Good.
Line 147 stream missing returns before session. Good.
Line 177 PR fetch failed returns before session. Good.
Line 191 head moved returns before session. Good.
Line 249 already finalized returns before session. Good (session created at 287 after).
After session creation, reconcileStream has try-catch so never throws or returns early in the outer function. So session always deleted at 438.

The most concrete finding: In idempotency guard (comment mode), if `getIssueComments` fails, it sets allComments=[] and continues. This means the botComment search will not find an existing finalization comment, so it will re-post. This is intended per comment, but if failure is frequent, duplicate comments could appear. Acceptable.

Another concern: In `parsePayload`, `input.number` is only checked typeof number, not finite/integer. Passing `NaN` or `Infinity` slips through, causing NaN in R2 keys and string interpolations. Concrete weak validation issue.

Also `input.headSha` not checked against hex string; arbitrary string becomes R2 key. Could be suggestion.

I think the cleanest finding is: markAutoReviewCompleted failure is logged and swallowed, allowing finalize to succeed while the slot remains unconsumed, which could trigger unintended re-reviews.
- **Fix:** Consider returning a failure/non-finalized reason when markAutoReviewCompleted fails, or queue a retry, since an unconsumed auto-review slot may cause duplicate/unintended reviews.

#### CR-a49b1d2042d9 · Streaming snippet does not consume stream
- **File:** `src/content/catalog-models/anthropic-claude-sonnet-5.json` line 410
- **Issue:** The `stream: true` TypeScript example assigns `env.AI.run(...)` to `response` and only calls `console.log(response)`. When streaming is enabled this returns a stream/response object, so logging it does not produce the streamed text shown in `output.text`.
- **Fix:** Update the TypeScript streaming snippet to consume the stream (for example, iterate over chunks or read `response.body`) so the example matches the rendered output.

#### CR-205ecfa2f49f · Added lines can be silently dropped
- **File:** `.flue/lib/code-review-inproc.ts` line 76
- **Issue:** The header-skip checks in parseAddedLines (e.g. raw.startsWith("+++ b/")) run on every patch line, not just on real file headers before the first hunk. An added line whose source content starts with "++ b/", "++ a/", etc. will appear in the patch as "+++ b/..." and be skipped, so it never reaches the reviewer.
- **Fix:** Track whether a hunk header has been seen and only apply the ---/+++ header skip rules before the first hunk.

#### CR-790138ed0478 · Timeout flag race misclassifies later errors
- **File:** `.flue/lib/code-review-inproc.ts` line 465
- **Issue:** If the per-file timer fires while handle has already resolved, timedOut is set to true but the function may still proceed to process the result. If any subsequent step (e.g. assignCodeReviewFindingIds) throws, the catch block reports it as a timeout instead of the real error.
- **Fix:** Reset timedOut = false immediately after await handle succeeds, before processing the result.

#### CR-86f40bf1274b · Finalize lock stuck on admission failure
- **File:** `.flue/lib/finalize-rendezvous.ts` line 391
- **Issue:** After `tryClaimFinalize` wins the conditional PUT, `admitWorkflow` is awaited outside the try/catch. If it throws, the `finalize.lock` object remains in R2 and no other specialist can claim it, so `finalize-review` is never admitted for this dispatch.
- **Fix:** Either wrap admission in a retry with exponential backoff, or delete/reset the lock in the admission error path so another retry can take over.

#### CR-45351e1f8985 · Self-stream final state not verified
- **File:** `.flue/lib/finalize-rendezvous.ts` line 203
- **Issue:** `tryClaimFinalize` checks that every sibling stream is `final: true`, but never verifies that the caller's own stream result exists and is final before racing for the lock.
- **Fix:** Verify `myStream`'s own payload is final in `tryClaimFinalize`, so the function is safe when called outside of `reportSpecialistResult` or after a delayed R2 read-your-write consistency window.

#### CR-ea45836bc4bb · Inconsistent example output
- **File:** `src/content/catalog-models/anthropic-claude-opus-4.8.json` line 508
- **Issue:** The added "Web Search" example's `output.text` only contains "I'll search for the latest Cloudflare news this week.", but the `raw_response.content` array (lines 688-792) contains the actual final answer with the three news bullets, tool-result payloads, and citations. The example output does not reflect the real model response it is paired with, making the catalog entry misleading.
- **Fix:** Update `output.text` to contain the complete final response text from the `raw_response` (the three bullets and closing sentence), matching how the other examples populate the `output` field.

#### CR-8c6d3f362c23 · Example output incomplete
- **File:** `src/content/catalog-models/anthropic-claude-haiku-4.5.json` line 481
- **Issue:** `output.text` is set to "Let me search for more recent news from this week specifically.", but the surrounding `raw_response.content` continues with the web_search tool result and a final answer beginning "Based on the latest news from this week..." (line 653). Other examples keep `output.text` aligned with the full assistant response.
- **Fix:** Update `output.text` to contain the final assistant answer, or adjust the example data so the output and raw_response represent the same turn.

### Suggestions (3)

#### CR-5da00f3a901d · Reduced motion animation not suppressed
- **File:** `src/components/AiSearchIndexingDiagram.astro` line 796
- **Issue:** The `@media (prefers-reduced-motion: reduce)` block removes transitions but does not suppress the `asid-pulse` keyframe animation on `.asid-node.current`. A user who toggles reduced motion after mount, or whose preference is missed by the one-time JS check, will still see the continuous pulse.
- **Fix:** Add `.asid-node.current { animation: none; }` inside the reduced motion media query. Consider also listening for `change` on the `matchMedia` query so the component reacts to live preference changes.

#### CR-52aaf6ceb860 · New web component directory convention
- **File:** `src/components/AiSearchIndexingDiagram.astro`
- **Issue:** The new web component is added as a flat file, `src/components/AiSearchIndexingDiagram.astro`. AGENTS.md directs new web components to be placed in `src/components/{component-name}/` directories.
- **Fix:** Move the component into `src/components/ai-search-indexing-diagram/` and update the barrel import in `src/components/index.ts` to match.

#### CR-c0ce4fd12e7d · Unused CSS custom property
- **File:** `src/components/AiSearchVoiceDiagram.astro` line 173
- **Issue:** `--asvd-accent-soft` is defined but never referenced anywhere in the component's CSS or markup.
- **Fix:** Remove the unused `--asvd-accent-soft` declaration or apply it where intended for consistency with the other AI Search diagrams.

---

## Conventions

### Warnings (1)

#### CV-8436dbf55b99 · Scope accuracy
- **File:** PR-level finding
- **Issue:** Description claims five modified pages including /spectrum/reference/limitations/ and /load-balancing/additional-options/spectrum/, but changedFiles does not include those paths.
- **Fix:** Update the Changes section to reflect the files actually modified in the PR, or add the omitted files if they were intended to be changed.

Code Review

This code review is in beta and may not always be helpful — use your judgment.

Warnings (11)
File Issue
spectrum/reference/troubleshooting.mdx line 63 Misleading cross-reference — Line 63 promises more details about the DNS-record conflict limitation and links to /spectrum/reference/limitations/, but the Limitations page does not mention this restriction. Fix: Either add the DNS-record conflict limitation to src/content/docs/spectrum/reference/limitations.mdx or remove the promise of more details and point the link elsewhere.
src/components/AiSearchIndexingDiagram.astro line 889 Unguarded custom element registrationcustomElements.define("cfdocs-ai-search-indexing-diagram", ...) is called unconditionally. If the script is evaluated more than once (e.g., during HMR, in tests, or if the script is otherwise duplicated), the custom element registry throws NotSupportedError. Fix: Make the registration idempotent: if (!customElements.get("cfdocs-ai-search-indexing-diagram")) { customElements.define(...); }.
src/components/AiSearchQueryingDiagram.astro line 789 Detached element timer leakdisconnectedCallback() only clears the single pending this.timer. A timeout callback that is already queued can still run after the element is removed, call advance(), and schedule new timers against a detached DOM tree. Fix: Guard advance() (and the initial play() callback) with a this.isConnected check, or clear/reset timers when disconnected and avoid scheduling further work.
.flue/workflows/finalize-review.ts line 146 Resource leak on failure path — When stream results are missing, cleanupPending is awaited then the function returns. But the agent session (created later) is irrelevant here. However, early returns after step 1 (e.g., context missing at line 101, stream missing at 147, PR fetch failed at 177, head moved at 191) leave no created session. The only real resource is the R2 bucket reads. Not a concern. However, when reconcileStream throws and we catch at lines 332-350, the function continues. That's intended degradation. Not a finding. Main concern: in step 8, markAutoReviewCompleted failure is caught and logged, but finalize continues and reports success. This silently leaves the auto-review slot unconsumed, which could cause the user to be re-billed/re-reviewed unexpectedly. This is error swallowing but explicitly logged as a non-fatal operation. Could be a warning. Also: line 438 await session.delete().catch(() => {}); swallows session deletion errors silently, but that's minor. More significant: parsePayload does not validate number > 0, headSha nonempty, dispatchId nonempty. However that's standard weak validation. Could be a suggestion. Most concrete issue: Late resource cleanup. When init(agent) at line 287 creates a harness/session and any later early return (after session creation) would leave the session active. Looking at code, after line 291 there are no early returns possible, except reconciler degradation which doesn't return. Actually there are no early returns after session creation. So OK. Wait - line 101 context missing returns before session creation. Good. Line 147 stream missing returns before session. Good. Line 177 PR fetch failed returns before session. Good. Line 191 head moved returns before session. Good. Line 249 already finalized returns before session. Good (session created at 287 after). After session creation, reconcileStream has try-catch so never throws or returns early in the outer function. So session always deleted at 438. The most concrete finding: In idempotency guard (comment mode), if getIssueComments fails, it sets allComments=[] and continues. This means the botComment search will not find an existing finalization comment, so it will re-post. This is intended per comment, but if failure is frequent, duplicate comments could appear. Acceptable. Another concern: In parsePayload, input.number is only checked typeof number, not finite/integer. Passing NaN or Infinity slips through, causing NaN in R2 keys and string interpolations. Concrete weak validation issue. Also input.headSha not checked against hex string; arbitrary string becomes R2 key. Could be suggestion. I think the cleanest finding is: markAutoReviewCompleted failure is logged and swallowed, allowing finalize to succeed while the slot remains unconsumed, which could trigger unintended re-reviews. Fix: Consider returning a failure/non-finalized reason when markAutoReviewCompleted fails, or queue a retry, since an unconsumed auto-review slot may cause duplicate/unintended reviews.
catalog-models/anthropic-claude-sonnet-5.json line 410 Streaming snippet does not consume stream — The stream: true TypeScript example assigns env.AI.run(...) to response and only calls console.log(response). When streaming is enabled this returns a stream/response object, so logging it does not produce the streamed text shown in output.text. Fix: Update the TypeScript streaming snippet to consume the stream (for example, iterate over chunks or read response.body) so the example matches the rendered output.
.flue/lib/code-review-inproc.ts line 76 Added lines can be silently dropped — The header-skip checks in parseAddedLines (e.g. raw.startsWith("+++ b/")) run on every patch line, not just on real file headers before the first hunk. An added line whose source content starts with "++ b/", "++ a/", etc. will appear in the patch as "+++ b/..." and be skipped, so it never reaches the reviewer. Fix: Track whether a hunk header has been seen and only apply the ---/+++ header skip rules before the first hunk.
.flue/lib/code-review-inproc.ts line 465 Timeout flag race misclassifies later errors — If the per-file timer fires while handle has already resolved, timedOut is set to true but the function may still proceed to process the result. If any subsequent step (e.g. assignCodeReviewFindingIds) throws, the catch block reports it as a timeout instead of the real error. Fix: Reset timedOut = false immediately after await handle succeeds, before processing the result.
.flue/lib/finalize-rendezvous.ts line 391 Finalize lock stuck on admission failure — After tryClaimFinalize wins the conditional PUT, admitWorkflow is awaited outside the try/catch. If it throws, the finalize.lock object remains in R2 and no other specialist can claim it, so finalize-review is never admitted for this dispatch. Fix: Either wrap admission in a retry with exponential backoff, or delete/reset the lock in the admission error path so another retry can take over.
.flue/lib/finalize-rendezvous.ts line 203 Self-stream final state not verifiedtryClaimFinalize checks that every sibling stream is final: true, but never verifies that the caller's own stream result exists and is final before racing for the lock. Fix: Verify myStream's own payload is final in tryClaimFinalize, so the function is safe when called outside of reportSpecialistResult or after a delayed R2 read-your-write consistency window.
catalog-models/anthropic-claude-opus-4.8.json line 508 Inconsistent example output — The added "Web Search" example's output.text only contains "I'll search for the latest Cloudflare news this week.", but the raw_response.content array (lines 688-792) contains the actual final answer with the three news bullets, tool-result payloads, and citations. The example output does not reflect the real model response it is paired with, making the catalog entry misleading. Fix: Update output.text to contain the complete final response text from the raw_response (the three bullets and closing sentence), matching how the other examples populate the output field.
catalog-models/anthropic-claude-haiku-4.5.json line 481 Example output incompleteoutput.text is set to "Let me search for more recent news from this week specifically.", but the surrounding raw_response.content continues with the web_search tool result and a final answer beginning "Based on the latest news from this week..." (line 653). Other examples keep output.text aligned with the full assistant response. Fix: Update output.text to contain the final assistant answer, or adjust the example data so the output and raw_response represent the same turn.
Suggestions (3)
File Issue
src/components/AiSearchIndexingDiagram.astro line 796 Reduced motion animation not suppressed — The @media (prefers-reduced-motion: reduce) block removes transitions but does not suppress the asid-pulse keyframe animation on .asid-node.current. A user who toggles reduced motion after mount, or whose preference is missed by the one-time JS check, will still see the continuous pulse. Fix: Add .asid-node.current { animation: none; } inside the reduced motion media query. Consider also listening for change on the matchMedia query so the component reacts to live preference changes.
src/components/AiSearchIndexingDiagram.astro New web component directory convention — The new web component is added as a flat file, src/components/AiSearchIndexingDiagram.astro. AGENTS.md directs new web components to be placed in src/components/{component-name}/ directories. Fix: Move the component into src/components/ai-search-indexing-diagram/ and update the barrel import in src/components/index.ts to match.
src/components/AiSearchVoiceDiagram.astro line 173 Unused CSS custom property--asvd-accent-soft is defined but never referenced anywhere in the component's CSS or markup. Fix: Remove the unused --asvd-accent-soft declaration or apply it where intended for consistency with the other AI Search diagrams.

Conventions

Warnings (1)
File Issue
PR Scope accuracy — Description claims five modified pages including /spectrum/reference/limitations/ and /load-balancing/additional-options/spectrum/, but changedFiles does not include those paths. Fix: Update the Changes section to reflect the files actually modified in the PR, or add the omitted files if they were intended to be changed.

Style Guide Review

No style-guide issues found.

Commands

Only codeowners can run commands. Post a comment with the command to trigger it.

Command Description
/review Runs a review now. Incremental if a prior review exists, full if not.
/full-review Re-reviews the entire PR diff from scratch, ignoring incremental history. Useful after a rebase, when you want a fresh review, or if the bot gets out of sync and reports issues that no longer exist.
/ignore-review-limit Permanently lifts the 2-review automatic limit for this PR. Future pushes will trigger reviews as normal.
/disable-auto-review Stops automatic reviews from triggering on future pushes to this PR. Codeowners can still run /review or /full-review manually.

@stechedo
stechedo force-pushed the spectrum-troubleshooting-docs branch from f311329 to 4e5ee85 Compare June 26, 2026 19:10
@stechedo
stechedo force-pushed the spectrum-troubleshooting-docs branch from ea9679c to ad01610 Compare July 14, 2026 20:11
@msimoncf

Copy link
Copy Markdown

Thanks Stephen, have reviewed.

Could we just hold the IP Access Rules + health checks section? I need a bit more time to verify the mechanism, but I don't want to block everything else.

For the rest:

1. Same-hostname clarification
Files: spectrum/reference/troubleshooting.mdx, dns/manage-dns-records/troubleshooting/records-with-same-name.mdx
The limitation is specifically about manually-created proxied DNS records colliding with Spectrum-managed records. Multiple Spectrum apps can share the same hostname, including HTTP/HTTPS + TCP/UDP apps, because Spectrum manages the DNS records.
Could we update the wording to something like:
Cloudflare does not support having both a manually-created proxied DNS record (A, AAAA, or CNAME) and a Spectrum application on the same hostname. This is because Spectrum provisions and manages its own DNS record for the application. Multiple Spectrum applications can share the same hostname.
And note that the split-hostname workaround is only needed when a manually-created proxied record must be kept.

(opencode picked up the below)
2. error 525 inconsistency
File: spectrum/reference/configuration-options.mdx
The troubleshooting page says TCP apps log 521/522 for origin TLS failures, while 525 is for HTTP/HTTPS apps. The caution in configuration-options.mdx currently says TCP double-proxy may result in 525, so the two pages contradict each other.
Could we align it to something like:
For TCP applications, a failed TLS handshake to the origin is reported as an origin connection failure (521 or 522). For HTTP/HTTPS applications, clients may receive error 525 (SSL handshake failed).

Thanks!

stechedo added a commit to stechedo/cloudflare-docs that referenced this pull request Jul 17, 2026
…split health checks

Per review feedback on cloudflare#30683:

- Move the 'Health checks fail when IP Access Rules are enabled'
  section and related callouts to a separate PR (cloudflare#32137) so this PR
  isn't blocked while the mechanism is verified.
- Clarify that the DNS record conflict is specifically between a
  manually-created proxied record and a Spectrum application, not
  between Spectrum applications themselves. Multiple Spectrum
  applications (including a mix of HTTP/HTTPS and TCP/UDP) can share
  a hostname because Spectrum manages the DNS record for each.
- Align the double-proxy caution in configuration-options.mdx with
  the troubleshooting page: TCP applications surface a failed origin
  TLS handshake as 521/522, not error 525, which is HTTP/HTTPS-app
  specific.
@stechedo

Copy link
Copy Markdown
Collaborator Author

Thanks for the review — pushed changes addressing both items, plus split out the held section.

1. Same-hostname clarification

Updated spectrum/reference/troubleshooting.mdx (Cannot create Spectrum application section) and dns/manage-dns-records/troubleshooting/records-with-same-name.mdx to make clear the conflict is specifically between a manually-created proxied record and a Spectrum application (Spectrum provisions/manages its own record), and that multiple Spectrum applications — HTTP/HTTPS and TCP/UDP alike — can share a hostname. The split-hostname workaround is now framed as only needed when you must keep a manually-created proxied record on the hostname.

2. Error 525 inconsistency

Aligned the double-proxy caution in spectrum/reference/configuration-options.mdx with the troubleshooting page: TCP applications surface a failed origin TLS handshake as 521/522, not 525525 is HTTP/HTTPS-application-specific.

Held section moved to a new PR

Split the "Health checks fail when IP Access Rules are enabled" content (troubleshooting.mdx section, the two callouts in configuration-options.mdx, and the Monitors-step callout in load-balancing/spectrum.mdx) out to #32137, so it doesn't block the rest of this PR while the mechanism is verified.

Re: the automated code review findings posted above

Those findings (CR-9746e1fd141a, CR-b72d87deb669, CR-a65044b3f463, CR-a49b1d2042d9, CR-205ecfa2f49f, CR-790138ed0478, CR-86f40bf1274b, CR-45351e1f8985, CR-ea45836bc4bb, CR-8c6d3f362c23, CR-5da00f3a901d, CR-52aaf6ceb860, CR-c0ce4fd12e7d) all reference files that are not part of this PR's diff (src/components/AiSearchIndexingDiagram.astro, .flue/workflows/finalize-review.ts, .flue/lib/*, src/content/catalog-models/anthropic-claude-*.json, etc. — this PR only touches 5 Spectrum/DNS docs pages). Skipping all of them as out of scope for this PR; flagging in case the review got attached to the wrong PR.

stechedo added 8 commits July 17, 2026 10:02
…se drivers

Based on analysis of April 2026 Network SBR cases, add documentation
to address the top 3 case-generating Spectrum issues:

1. IP Access Rules + Health Checks interaction: Customers enable IP
   Access Rules on Spectrum apps, then Cloudflare health checks fail
   because probe IPs are blocked. Added warnings to configuration-options
   and load-balancing/spectrum pages.

2. Same hostname for WAF + Spectrum: Customers attempt to use the same
   hostname for HTTP (WAF) and TCP (Spectrum) on different ports. This
   is a platform limitation. Added new section to limitations page and
   cross-reference on DNS troubleshooting page.

3. Edge TLS / Protocol mismatch: Customers configure HTTP edge ports
   expecting HTTPS to origin. Spectrum does not upgrade protocols.
   Added warnings to Edge TLS Termination section.

Also:
- Created new /spectrum/reference/troubleshooting/ page with structured
  symptom/cause/solution sections for all three issues plus error 525
  and common status code patterns
- Added note to /spectrum/reference/logs/ clarifying that Spectrum
  status codes are distinct from HTTP status codes
Fix style guide violations flagged by cloudflare-docs-bot:
- Use 'turn on' instead of 'enable' for toggles
- Use bullet points for unordered causes, numbered list for sequential steps
- Remove -ing verb from heading ('Understanding common...' -> 'Common...')
- Replace 'the table below' with direct reference
- Replace 'etc.' with 'and similar'
- Monospace DNS record types (A, AAAA, CNAME)
- Add introductory sentence before status code table
- Convert two-item symptom list to prose
- Fix TLS mode guidance to specify Full/Full (Strict) instead of generic 'enabled'
- Fix broken cross-links to removed limitations.mdx anchors
- Reframe error 525 section around TLS handshake failures with
  Spectrum event log code 540, clarify HTTP 525 applies only to
  HTTP/HTTPS-type applications
- Update DNS records-with-same-name cross-link to point to the
  troubleshooting page (which documents the workaround) instead
  of the limitations page (which does not)
- Monospace status code examples (444, 499) in logs.mdx
- Update anchor in configuration-options.mdx to match renamed heading
…ection

Replace 540 (client/edge TLS failure) with origin-side error codes
520/521/522 which correctly describe edge-to-origin connection failures.
540 refers to the client-to-edge handshake per the Spectrum logs
reference, not edge-to-origin.
Separate TCP and HTTP/HTTPS symptoms: Edge TLS Termination applies
to TCP apps (origin errors 521/522), while error 525 applies to
HTTP/HTTPS apps. Avoids conflating transport-level connection codes
with TLS handshake failures.
Spectrum has no dedicated origin-side TLS handshake status code.
A failed TLS handshake at the origin is reported as an origin
connection failure (521/522). Added explanation and cross-link
to the Event logs reference.
…split health checks

Per review feedback on cloudflare#30683:

- Move the 'Health checks fail when IP Access Rules are enabled'
  section and related callouts to a separate PR (cloudflare#32137) so this PR
  isn't blocked while the mechanism is verified.
- Clarify that the DNS record conflict is specifically between a
  manually-created proxied record and a Spectrum application, not
  between Spectrum applications themselves. Multiple Spectrum
  applications (including a mix of HTTP/HTTPS and TCP/UDP) can share
  a hostname because Spectrum manages the DNS record for each.
- Align the double-proxy caution in configuration-options.mdx with
  the troubleshooting page: TCP applications surface a failed origin
  TLS handshake as 521/522, not error 525, which is HTTP/HTTPS-app
  specific.
@stechedo
stechedo force-pushed the spectrum-troubleshooting-docs branch from 426e94b to effc1d7 Compare July 17, 2026 14:03
@steve-cloudflare
steve-cloudflare enabled auto-merge (squash) July 17, 2026 14:40
@github-actions github-actions Bot removed the stale label Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

product:dns Issues or PRs related to DNS product:load-balancing Related to Load Balancing product product:network product:spectrum Related to Spectrum product size/m

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants