{"record":{"id":"7bfcf55906e1f83e","repo":"FoundationAgents/MetaGPT","slug":"expecting-property-name-enclosed-in-double-quotes","errorCode":null,"errorMessage":"Expecting property name enclosed in double quotes","messagePattern":"Expecting property name enclosed in double quotes","errorType":"exception","errorClass":"JSONDecodeError","httpStatus":null,"severity":"error","filePath":"metagpt/utils/custom_decoder.py","lineNumber":137,"sourceCode":"    # Use a slice to prevent IndexError from being raised, the following\n    # check will raise a more specific ValueError if the string is empty\n    nextchar = s[end : end + 1]\n    # Normally we expect nextchar == '\"'\n    if nextchar != '\"' and nextchar != \"'\":\n        if nextchar in _ws:\n            end = _w(s, end).end()\n            nextchar = s[end : end + 1]\n        # Trivial empty object\n        if nextchar == \"}\":\n            if object_pairs_hook is not None:\n                result = object_pairs_hook(pairs)\n                return result, end + 1\n            pairs = {}\n            if object_hook is not None:\n                pairs = object_hook(pairs)\n            return pairs, end + 1\n        elif nextchar != '\"':\n            raise JSONDecodeError(\"Expecting property name enclosed in double quotes\", s, end)\n    end += 1\n    while True:\n        if end + 1 < len(s) and s[end] == nextchar and s[end + 1] == nextchar:\n            # Handle the case where the next two characters are the same as nextchar\n            key, end = scanstring(s, end + 2, strict, delimiter=nextchar * 3)\n        else:\n            # Handle the case where the next two characters are not the same as nextchar\n            key, end = scanstring(s, end, strict, delimiter=nextchar)\n        key = memo_get(key, key)\n        # To skip some function call overhead we optimize the fast paths where\n        # the JSON key separator is \": \" or just \":\".\n        if s[end : end + 1] != \":\":\n            end = _w(s, end).end()\n            if s[end : end + 1] != \":\":\n                raise JSONDecodeError(\"Expecting ':' delimiter\", s, end)\n        end += 1\n\n        try:","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/FoundationAgents/MetaGPT/blob/11cdf466d042aece04fc6cfd13b28e1a70341b1f/metagpt/utils/custom_decoder.py#L119-L155","documentation":"This comes from MetaGPT's custom JSON decoder (metagpt/utils/custom_decoder.py), a fork of the stdlib json scanner that additionally supports single-quoted/quote-delimited keys. After parsing an object's opening quote character, if the first non-whitespace token is not a closing brace or a quote, it raises JSONDecodeError('Expecting property name enclosed in double quotes').","triggerScenarios":"Decoding '{a: 1}' (bare unquoted key); '{1: \"x\"}' (numeric key); '{,}' or '{:}' stray punctuation; '{\"a\": 1,}' trailing comma before } — nextchar is ',' which is neither '\"' nor '}'.","commonSituations":"LLM emits JSON with unquoted keys or a trailing comma; the relaxed decoder handles single quotes but NOT bare keys or trailing commas, so 'python-repr-like' dictionaries fail; text extracted from markdown retains a stray character after '{'.","solutions":["Inspect the exact character at the reported error position (the exception carries lineno/colno).","Quote all keys and remove trailing commas: '{\"a\": 1}' not '{a: 1,}'.","Pre-clean LLM output: json5-style repair or a regex to quote bare keys before decoding.","Use standard double quotes throughout and validate with python -m json.tool."],"exampleFix":"# before\nloads(\"{a: 1,}\")  # bare key + trailing comma -> JSONDecodeError\n\n# after\nloads('{\"a\": 1}')","handlingStrategy":"try-catch","validationCode":"import re\n\ndef quote_bare_keys(text: str) -> str:\n    # quote bare keys and drop trailing commas for decoder compatibility\n    text = re.sub(r\"([{,]\\s*)([A-Za-z_]\\w*)(\\s*:)\", r'\\1\"\\2\"\\3', text)\n    return re.sub(r\",(\\s*[}\\]])\", r\"\\1\", text)","typeGuard":null,"tryCatchPattern":"from json import JSONDecodeError\ntry:\n    obj = loads(text)\nexcept JSONDecodeError as e:\n    if e.msg.startswith(\"Expecting property name\"):\n        obj = loads(quote_bare_keys(text))  # repair and retry once","preventionTips":["Require double-quoted keys and no trailing commas in LLM JSON output.","Use the exception's lineno/colno to pinpoint the offending character.","Remember the custom decoder accepts single-quoted keys but not bare keys or trailing commas."],"tags":["metagpt","json","llm-output","parsing","custom-decoder"],"backgroundTag":null,"analyzedSha":"11cdf466d042aece04fc6cfd13b28e1a70341b1f","analyzedAt":"2026-08-14T23:20:02.994Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}