Diagnostic codes are the stable handle for compiler, parser, build, and editor findings. Use them for bug reports, editor integrations, CI policy, and user-facing help.
Explain A Code
Use gowdk explain when a diagnostic includes a code:
gowdk explain missing_ssr_addon
gowdk explain --json spa_dynamic_route_missing_paths
Plain text is for humans. --json is for editors and tools.
Unknown codes return a non-zero exit status with close-code suggestions:
gowdk explain missing_ssr_adon
JSON Shape
gowdk explain --json <code> prints:
{
"code": "missing_ssr_addon",
"area": "rendering",
"stability": "stable",
"severity": "error",
"summary": "request-time page behavior requires the SSR addon",
"details": "The source selects request-time page rendering...",
"nextSteps": [
"Enable ssr.Addon() in gowdk.config.go when request-time page rendering is intentional."
],
"invalid": "...",
"fixed": "..."
}
Optional fields are omitted when no detailed explanation exists yet.
Registry Source
The implementation source of truth is internal/diagnostics/registry.go.
The registry stores:
code: lower snake case diagnostic ID.area: broad subsystem such asparser,routing,components, orcontracts.stability: compatibility level.severity: default severity, one oferror,warning, orinfo.fix: optional safe rewrite metadata with a title, description, and named rewriter.summary: short description.
go test ./internal/diagnostics scans non-test Go source for emitted
diagnostic-code literals and fails when a new emitted code is missing from the
registry.
Stability
stable: safe for CLI, editor, and docs references during the 0.x line unless release notes call out a migration.experimental: emitted by partial feature slices and may change while the feature hardens.addon: emitted by addon-owned validation or fallback addon diagnostics.
Most diagnostics use severity error. Accessibility diagnostics and
guardless-page diagnostics can use severity warning; route-mode notes can use
severity info. Warnings are reported by gowdk check but do not make the
command fail unless --warnings-as-errors is passed.
Fixes
Some diagnostics have registry-backed fixes. gowdk fix applies those safe
single-file rewrites, and LSP code actions use the same metadata:
gowdk fix --dry-run --code old_action_block_syntax
gowdk fix --code unknown_gowdk_use_alias
Old endpoint syntax fixes migrate empty blocks. Blocks that still contain behavior are refused because moving behavior into Go is not mechanically safe.
Naming
Code names use lower snake case. Prefer predictable forms:
<surface>_<problem>, such ascomponent_field_error.duplicate_<thing>,missing_<thing>,unknown_<thing>,invalid_<thing>, andunsupported_<thing>.<feature>_requires_<dependency>.
Parser diagnostics emit stable codes for common unsupported syntax and keep
parse_error as the fallback for unknown parser failures.
Current Areas
- Parser and lexer:
parse_error,package_must_be_first,malformed_package_declaration,malformed_legacy_metadata,old_action_block_syntax,old_api_block_syntax,malformed_go_import,malformed_gowdk_use,unsupported_literal_record_syntax,unsupported_top_level_block,unsupported_layout_metadata,invalid_component_prop,unsupported_component_prop_type,unterminated_string. - Packages and imports:
missing_package_declaration,package_mismatch,go_package_error,invalid_go_import,duplicate_go_import_alias. - GOWDK source imports:
duplicate_gowdk_use_alias,unknown_gowdk_use_package,unknown_gowdk_use_alias,unknown_gowdk_component,unsupported_gowdk_use_scope. - Pages, routes, guards, and render lanes:
duplicate_page_id,malformed_route,duplicate_route_param,duplicate_route,ambiguous_dynamic_route,route_method_conflict,missing_view_block,missing_ssr_addon,spa_dynamic_route_missing_paths,server_requires_request_render,spa_disabled,ssr_disabled,missing_page_guard,public_guard_exclusive, andguard_requires_request_render. - Server-lane view directives (
g:for/g:ifoverserver {}data):server_for_invalid,server_for_nested_scope,server_if_invalid,server_if_nested_scope,server_load_field_conflict,server_region_directive,server_url_tainted,ghtml_over_load_data. - Backend endpoints:
invalid_backend_handler_name,invalid_go_endpoint_handler,malformed_go_endpoint_comment,go_endpoint_parse_error,duplicate_go_endpoint_comment,unsupported_action_method,backend_binding_required,unsupported_backend_signature,unexported_backend_handler,ambiguous_backend_handler. - Layouts, CSS, and cache:
duplicate_layout_id,unknown_layout_id,invalid_css_selection,duplicate_css_selection,revalidate_requires_cache,duplicate_revalidate_policy. - Components, stores, and markup:
duplicate_component_name,redundant_component_implementation,component_contract_error,component_field_error,component_client_error,component_composition_cycle,duplicate_component_emit,duplicate_page_store,page_store_error,page_store_persist_key_conflict,page_store_persist_scope_conflict,page_store_persist_scope_invalid,page_store_persist_secret_field,unknown_component_store,view_parse_error. - Accessibility:
missing_img_alt,missing_form_label,empty_link_text,missing_button_type,heading_order_skip. - Go blocks and generated app wiring:
invalid_go_block,go_client_requires_page,go_ssr_requires_request_render,unknown_go_block_target,unknown_addon_go_block_target,unsupported_addon_go_block_target,addon_go_block_diagnostic,generated_app_import_cycle. - Partials and fragments:
unsupported_fragment_method. - Contracts:
contract_handler_invalid,contract_handler_missing,contract_type_invalid,contract_result_invalid,contract_input_invalid,contract_event_name_invalid,contract_event_category_invalid,duplicate_command_owner,contract_route_invalid,contract_reference_missing,contract_reference_invalid,contract_reference_role_not_allowed. - Realtime:
missing_realtime_addon,realtime_subscription_parse_error,realtime_subscription_missing,realtime_subscription_invalid,realtime_subscription_role_not_allowed. - Contract web adapters:
ssr_command_no_client(a request-time page declares ag:commandwrite form with nog:queryregion for it to refresh, so the write is non-reactive and falls back to raw JSON when JavaScript is disabled). - WASM and browser Go:
unsupported_wasm_import,wasm_package_build_error,wasm_package_entrypoint_error,wasm_package_export_error,client_go_block_wasm_source_error,client_go_block_wasm_build_error,client_go_block_wasm_entrypoint_error,client_go_block_wasm_import_error,client_go_block_wasm_export_error. - Security audit (
gowdk audit):audit_action_missing_csrf,audit_api_missing_csrf,audit_api_public_by_omission,audit_command_missing_csrf,audit_contract_roleless,audit_guardless_endpoint_page,audit_bundle_secret,audit_client_route_unguarded,audit_headers_missing,audit_headers_runtime_missing,audit_raw_html_sink,audit_max_body_exceeds_policy,audit_public_not_allowed,audit_required_guard_missing,audit_runtime_mismatch,audit_test_failed,policy_duplicate_name,policy_extends_cycle,policy_unknown_extends,policy_unknown_selector,policy_selector_matched_nothing. These are experimental and emitted bygowdk audit, declared audit policies, or the optional runtime audit test runner.
Source Ranges
Diagnostics carry an exact source span (internal/source.SourceSpan) when one
is available at the emit site; the LSP and dev overlay use it directly and fall
back to a file/owner-level range only when no precise span exists.
Exact ranges now cover the backend-binding family, which point at the declaring
act / api / fragment block (or standalone //gowdk: endpoint):
ambiguous_backend_handler, unsupported_backend_signature,
unexported_backend_handler, and backend_binding_required. The
source.BackendBinding produced by compiler.BindBackendHandlers captures the
block span so both gowdk check/build diagnostics and the editor highlight the
exact declaration.
Exact ranges also cover g:for / g:key row bodies (component_field_error).
Errors inside a list row — invalid g:on: handlers, g:if / g:else-if
conditionals, g:bind:value / g:bind:checked targets, class: / style:
toggles, reactive attribute expressions, and {} interpolations — point at the
offending expression or text node. The view-contract collector skips loop
subtrees, so the list-directive validator is the only source for these and used
to fall back to the whole view {} block; it now maps the parsed
viewmodel.Attr / text offsets through componentViewBodyOffsetSpan.
Known gaps (no precise span available; file/owner- or line-level only):
go_package_errorfor an unparseable sibling.gofile or a missing package clause — these arise before a Go AST exists, so only the file path is known. Inlinego {}block package errors already carry the block span.- Go contract-scan diagnostics (
contract_handler_*,contract_reference_*,duplicate_command_owner, and peers frominternal/contractscan) carry the registration call's line and column but no end, so the editor marks a point rather than a token range.contractscan.Diagnosticrecords onlyLine/Column; an exact range needs the Go AST node end threaded through the scan report model. - Untyped parser errors (
parse_error) wrapped withwithLineininternal/parser(currently three call sites) carry only a line number, so the range is the whole line. Most parser diagnostics are typed vialineDiagnosticErrorand are already exact. - Component
client {}block errors (component_client_error) are line-accurate but not column-accurate:clientlang.SpancarriesStartLine/EndLineonly. - Interpolation errors inside a list row resolve to the enclosing text node or
attribute, not the individual
{expr}, when several interpolations share one node.
The LSP (internal/lsp/diagnostics.go) consumes Diagnostic.Range directly and
only derives a position-based range when Range is nil, so there is no
editor-only range guessing for diagnostics. Cursor-driven features
(hover, go-to-definition, find-references) still locate the token under the
caret by scanning, which is inherent to those features and unrelated to
diagnostic ranges.
Adding A Code
When adding or renaming a diagnostic code:
- Add or update the registry entry in
internal/diagnostics/registry.go, including severity and any safe fix metadata. - Add or update
gowdk explaindetail when the next step is not obvious. - Update this page when a new area or stability rule appears.
- Run
go test ./internal/diagnostics.