{"record":{"id":"9ab2b64a2a683a94","repo":"juicedata/juicefs","slug":"hex-expected-c","errorCode":null,"errorMessage":"hex expected: %c","messagePattern":"hex expected: %c","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/meta/dump.go","lineNumber":207,"sourceCode":"\t\t\tescValue = append(escValue, CHARS[c&0xF])\n\t\t} else if escValue != nil {\n\t\t\tn := utf8.RuneLen(r)\n\t\t\tescValue = append(escValue, original[i:i+n]...)\n\t\t}\n\t}\n\tif escValue == nil {\n\t\treturn original\n\t}\n\treturn string(escValue)\n}\n\nfunc parseHex(c byte) (byte, error) {\n\tif c >= '0' && c <= '9' {\n\t\treturn c - '0', nil\n\t} else if c >= 'A' && c <= 'F' {\n\t\treturn 10 + (c - 'A'), nil\n\t} else {\n\t\treturn 0, fmt.Errorf(\"hex expected: %c\", c)\n\t}\n}\n\nfunc unescape(s string) []byte {\n\tif !strings.ContainsRune(s, '%') {\n\t\treturn []byte(s)\n\t}\n\n\tp := []byte(s)\n\tn := 0\n\tfor i := 0; i < len(p); i++ {\n\t\tc := p[i]\n\t\tif c == '%' && i+2 < len(p) {\n\t\t\th, e1 := parseHex(p[i+1])\n\t\t\tl, e2 := parseHex(p[i+2])\n\t\t\tif e1 == nil && e2 == nil {\n\t\t\t\tc = h*16 + l\n\t\t\t\ti += 2","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/meta/dump.go#L189-L225","documentation":"Returned by parseHex in pkg/meta/dump.go when a character in an %-escaped string is not a valid hex digit (0-9, A-F). unescape() decodes '%XX' sequences while parsing a metadata dump; a malformed escape produces this error.","triggerScenarios":"Loading (`juicefs load`) a dumped metadata file whose names/chunks contain invalid percent-escapes such as '%G1' or a trailing '%' followed by a non-hex byte.","commonSituations":"Hand-edited dumps, dumps truncated/corrupted in transfer, or dumps produced by non-standard tools that percent-encode differently.","solutions":["Fix the invalid %XX escape in the dump file (use uppercase hex digits 0-9 A-F)","Re-dump the metadata from the live engine with `juicefs dump` instead of repairing manually","Validate the file was not truncated or mangled by editors/transfer encoding"],"exampleFix":"// before (invalid escape in dump)\n\"name\": \"file%G1.txt\"\n// after\n\"name\": \"file%47%31.txt\"","handlingStrategy":"validation","validationCode":"// validate percent-escapes before load\nfor i := 0; i+2 < len(s); i++ { if s[i]=='%' && !isHex(s[i+1])|!isHex(s[i+2]) { return fmt.Errorf(\"bad escape at %d\", i) } }","typeGuard":"func validHexEscapes(s string) bool { for i:=0;i+2<len(s);i++ { if s[i]=='%' { if !isHex(s[i+1]) || !isHex(s[i+2]) { return false }; i+=2 } }; return true }","tryCatchPattern":"if err := juicefsLoad(dumpFile); err != nil { if strings.Contains(err.Error(), \"hex expected\") { /* repair the dump or re-dump */ } }","preventionTips":["Never hand-edit dump files; re-dump from the live engine","Verify dump integrity (checksum) after transfer","Use ASCII-safe editors if a dump must be inspected"],"tags":["hex","parsing","dump"],"backgroundTag":"invalid-argument-format","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}