{"record":{"id":"8145faf2d43a82d0","repo":"floci-io/floci","slug":"invalid-awsphone","errorCode":null,"errorMessage":"Invalid AWSPhone: {}","messagePattern":"Invalid AWSPhone: (.+?)","errorType":"validation","errorClass":"CoercingParseValueException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/services/appsync/graphql/scalars/AppSyncScalars.java","lineNumber":229,"sourceCode":"            }\n        })\n        .build();\n\n    private static final Pattern PHONE_PATTERN = Pattern.compile(\"^\\\\+[1-9]\\\\d{1,14}$\");\n\n    public static final GraphQLScalarType AWS_PHONE = GraphQLScalarType.newScalar()\n        .name(\"AWSPhone\")\n        .description(\"An E.164 phone number\")\n        .coercing(new Coercing<String, String>() {\n            @Override\n            public String serialize(Object dataFetcherResult) {\n                return dataFetcherResult != null ? dataFetcherResult.toString() : null;\n            }\n            @Override\n            public String parseValue(Object input) {\n                String str = input.toString();\n                if (!PHONE_PATTERN.matcher(str).matches())\n                    throw new CoercingParseValueException(\"Invalid AWSPhone: \" + str);\n                return str;\n            }\n            @Override\n            public String parseLiteral(Object input) {\n                if (!(input instanceof StringValue sv)) return null;\n                return parseValue(sv.getValue());\n            }\n        })\n        .build();\n\n    private static final Pattern IPV4_PATTERN = Pattern.compile(\n        \"^(?:(?:25[0-5]|2[0-4]\\\\d|[01]?\\\\d\\\\d?)\\\\.){3}(?:25[0-5]|2[0-4]\\\\d|[01]?\\\\d\\\\d?)$\");\n    private static final Pattern IPV6_PATTERN = Pattern.compile(\n        \"^[0-9a-fA-F:]+$\");\n\n    public static final GraphQLScalarType AWS_IP_ADDRESS = GraphQLScalarType.newScalar()\n        .name(\"AWSIPAddress\")\n        .description(\"An IPv4 or IPv6 address\")","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/services/appsync/graphql/scalars/AppSyncScalars.java#L211-L247","documentation":"Thrown by the AWSPhone scalar's parseValue when the string does not match the E.164 pattern ^\\+[1-9]\\d{1,14}$ — a plus sign, a non-zero-leading country code, and 1–14 further digits, with nothing else. The scalar enforces canonical E.164 format.","triggerScenarios":"A GraphQL request sends \"555-123-4567\" (no +country code), \"+1 (555) 123-4567\" (spaces/parens/dashes), \"0123456789\" (leading zero after + is rejected), or \"+1\" (no subscriber digits) as an AWSPhone variable.","commonSituations":"Saving as-typed user input from phone widgets that format for display (dashes, spaces, parentheses); national numbers without country code; extensions appended like \"+14155551234x99\"; leading zeros or shorter-than-expected numbers in test data.","solutions":["Canonicalize to E.164 before sending: strip everything except digits, prepend country code and + (libraries like libphonenumber do this reliably)","Reject display-formatted strings client-side with your own validation","Do not append extensions (x99); store them in a separate field","Unit-test canonicalization with typical input formats"],"exampleFix":"// before\nString phone = \"+1 (555) 123-4567\"; // punctuation -> throws\n\n// after\nString phone = \"+15551234567\"; // digits only with country code","handlingStrategy":"validation","validationCode":"static String toE164(String raw, String defaultRegion) {\n    var p = com.google.i18n.phonenumbers.PhoneNumberUtil.getInstance().parse(raw, defaultRegion);\n    return com.google.i18n.phonenumbers.PhoneNumberUtil.getInstance().format(p, PhoneNumberFormat.E164);\n} // or: \"+\" + raw.replaceAll(\"\\\\D\", \"\")","typeGuard":"const isAwsPhone = (s: string): boolean => /^\\+[1-9]\\d{1,14}$/.test(s);","tryCatchPattern":"catch (CoercingParseValueException e) { // input not canonical: run E164 normalization, then retry }","preventionTips":["Canonicalize with libphonenumber before persisting or sending","Reject display formats (dashes, spaces, parens) at the input boundary","Store extensions in a separate field"],"tags":["graphql","appsync","awsphone","e164","phone","validation"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}