diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml
index 3a4e4163826432c19b362fe3d2efdb78d1c5c1d6..e2e86db52705d47963c5cd67d46c29730685081f 100644
--- a/CHANGELOG.next.toml
+++ b/CHANGELOG.next.toml
@@ -11,6 +11,18 @@
 # meta = { "breaking" = false, "tada" = false, "bug" = false }
 # author = "rcoh"
 
+[[aws-sdk-rust]]
+message = "Generated docs should no longer contain links that don't go anywhere"
+references = ["aws-sdk-rust#357"]
+meta = { "breaking" = false, "tada" = false, "bug" = true }
+author = "Velfi"
+
+[[smithy-rs]]
+message = "Generated docs will convert `<a>` tags with no `href` attribute to `<pre>` tags"
+references = ["aws-sdk-rust#357"]
+meta = { "breaking" = false, "tada" = false, "bug" = true }
+author = "Velfi"
+
 [[smithy-rs]]
 message = "Made fluent operation structs cloneable"
 references = ["aws-sdk-rust#254"]
diff --git a/codegen/build.gradle.kts b/codegen/build.gradle.kts
index db7bad3b0731ba7befa7ecf1b7b6a5406cfb7a0f..ffdbb977b9d18a97e0c29078e168606e57031561 100644
--- a/codegen/build.gradle.kts
+++ b/codegen/build.gradle.kts
@@ -22,6 +22,7 @@ val kotestVersion: String by project
 
 dependencies {
     implementation(kotlin("stdlib-jdk8"))
+    implementation("org.jsoup:jsoup:1.14.3")
     api("software.amazon.smithy:smithy-codegen-core:$smithyVersion")
     api("com.moandjiezana.toml:toml4j:0.7.2")
     implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion")
diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt
index 40082645d878a8cc4af85743ee1ed6faea4a6e51..8f8f3a9c1aad7b69bd5fdb8c37b68750eca97336 100644
--- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt
+++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt
@@ -6,6 +6,8 @@
 package software.amazon.smithy.rust.codegen.rustlang
 
 import org.intellij.lang.annotations.Language
+import org.jsoup.Jsoup
+import org.jsoup.nodes.Element
 import software.amazon.smithy.codegen.core.CodegenException
 import software.amazon.smithy.codegen.core.Symbol
 import software.amazon.smithy.codegen.core.writer.CodegenWriter
@@ -212,7 +214,7 @@ fun <T : CodeWriter> T.documentShape(shape: Shape, model: Model, autoSuppressMis
     when (docTrait?.value?.isNotBlank()) {
         // If docs are modeled, then place them on the code generated shape
         true -> {
-            this.docs(escape(docTrait.value))
+            this.docs(normalizeHtml(escape(docTrait.value)))
             note?.also {
                 // Add a blank line between the docs and the note to visually differentiate
                 write("///")
@@ -260,6 +262,29 @@ fun <T : CodeWriter> T.docs(text: String, vararg args: Any, newlinePrefix: Strin
 /** Escape the [expressionStart] character to avoid problems during formatting */
 fun CodeWriter.escape(text: String): String = text.replace("$expressionStart", "$expressionStart$expressionStart")
 
+/** Parse input as HTML and normalize it */
+fun normalizeHtml(input: String): String {
+    val doc = Jsoup.parse(input)
+    doc.body().apply {
+        normalizeAnchors() // Convert anchor tags missing href attribute into pre tags
+    }
+
+    return doc.body().html()
+}
+
+private fun Element.normalizeAnchors() {
+    getElementsByTag("a").forEach {
+        val link = it.attr("href")
+        if (link.isBlank()) {
+            it.changeInto("code")
+        }
+    }
+}
+
+private fun Element.changeInto(tagName: String) {
+    replaceWith(Element(tagName).also { elem -> elem.appendChildren(childNodesCopy()) })
+}
+
 /**
  * Write _exactly_ the text as written into the code writer without newlines or formatting
  */