{"record":{"id":"69a0db81d60ade52","repo":"dianping/cat","slug":"attribute-value-must-after","errorCode":null,"errorMessage":"attribute value must after \"=\"","messagePattern":"attribute value must after \"=\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cat-home/src/main/webapp/assets/js/editor/worker-xml.js","lineNumber":1539,"sourceCode":"\t\tcase '\"':\n\t\t\tif(s === S_EQ){//equal\n\t\t\t\tstart = p+1;\n\t\t\t\tp = source.indexOf(c,start)\n\t\t\t\tif(p>0){\n\t\t\t\t\tvalue = source.slice(start,p).replace(/&#?\\w+;/g,entityReplacer);\n\t\t\t\t\tel.add(attrName,value,start-1);\n\t\t\t\t\ts = S_E;\n\t\t\t\t}else{\n\t\t\t\t\tthrow new Error('attribute value no end \\''+c+'\\' match');\n\t\t\t\t}\n\t\t\t}else if(s == S_V){\n\t\t\t\tvalue = source.slice(start,p).replace(/&#?\\w+;/g,entityReplacer);\n\t\t\t\tel.add(attrName,value,start);\n\t\t\t\terrorHandler.warning('attribute \"'+attrName+'\" missed start quot('+c+')!!');\n\t\t\t\tstart = p+1;\n\t\t\t\ts = S_E\n\t\t\t}else{\n\t\t\t\tthrow new Error('attribute value must after \"=\"');\n\t\t\t}\n\t\t\tbreak;\n\t\tcase '/':\n\t\t\tswitch(s){\n\t\t\tcase S_TAG:\n\t\t\t\tel.setTagName(source.slice(start,p));\n\t\t\tcase S_E:\n\t\t\tcase S_S:\n\t\t\tcase S_C:\n\t\t\t\ts = S_C;\n\t\t\t\tel.closed = true;\n\t\t\tcase S_V:\n\t\t\tcase S_ATTR:\n\t\t\tcase S_ATTR_S:\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(\"attribute invalid close char('/')\")\n\t\t\t}","sourceCodeStart":1521,"sourceCodeEnd":1557,"githubUrl":"https://github.com/dianping/cat/blob/e815e74d4c2dd74edac831241f1253fcc7d25381/cat-home/src/main/webapp/assets/js/editor/worker-xml.js#L1521-L1557","documentation":"Quote character in an illegal position in the XML worker's attribute state machine (worker-xml.js:~1539). Quotes are only meaningful right after '=' (S_EQ, opening a value) or while scanning an unquoted value (S_V). A quote in any other state — before '=', after a completed value, inside a name — is a hard error.","triggerScenarios":"Malformed tags like '<tag \"foo\">' (quoted name), '<tag a=\"1\" \"2\">' (second value with no attribute), or '<tag a= \"1\" 2=\"3\">' sequences. Both quote cases at line 1518-1523 fall through to the else at line 1537-1539 and throw.","commonSituations":"HTML habits carried into strict XML (e.g. quoted attribute names), broken find/replace over attributes, or paste of rich text that turned apostrophes into typographic quotes (‘ ’) adjacent to attributes.","solutions":["Rewrite the start tag in well-formed form: name=\"value\" pairs only.","Check for stray/typographic quote characters in the flagged tag and replace with ASCII quotes.","Validate the document with xmllint to see all malformed spots at once."],"exampleFix":"<!-- before -->\n<input \"text\" value=\"1\">\n\n<!-- after -->\n<input type=\"text\" value=\"1\">","handlingStrategy":"validation","validationCode":"// Reject quotes that appear anywhere except around a value:\nfunction tagShapeOk(tagText) {\n  const body = tagText.replace(/^<\\s*[\\w:.-]+/, '').replace(/\\/?\\s*>$/, '');\n  const attrs = body.trim();\n  if (!attrs) return true;\n  return attrs.split(/\\s+(?=[\\w:.-]+\\s*=)/).every(a => /^[\\w:.-]+\\s*=\\s*(\"[^\"]*\"|'[^']*'|\\S+)$/.test(a));\n}","typeGuard":null,"tryCatchPattern":"try {\n  parseStartTag(source, start, tagNameReplacer);\n} catch (ex) {\n  if (/attribute value must after/.test(ex.message)) reportXmlError(ex); else throw ex;\n}","preventionTips":["Attribute names are bare identifiers — never quote them.","Normalize typographic quotes to ASCII when pasting content.","Use editor XML mode autoclosing so quotes land only around values."],"tags":["xml","sax","ace-editor","attributes","parser"],"backgroundTag":null,"analyzedSha":"e815e74d4c2dd74edac831241f1253fcc7d25381","analyzedAt":"2026-08-14T14:22:34.512Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}