{"record":{"id":"ab32ed0f9aa67e4d","repo":"bytebase/bytebase","slug":"type-q-expected-typecast-got-t","errorCode":null,"errorMessage":"type %q: expected TypeCast, got %T","messagePattern":"type %q: expected TypeCast, got %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/plugin/parser/pg/query_span_loader_type_name.go","lineNumber":48,"sourceCode":"\t\treturn nil, errors.Wrapf(err, \"parse type %q\", typeStr)\n\t}\n\tif len(stmts) != 1 {\n\t\treturn nil, errors.Errorf(\"type %q: expected 1 statement, got %d\", typeStr, len(stmts))\n\t}\n\tsel, ok := stmts[0].AST.(*ast.SelectStmt)\n\tif !ok {\n\t\treturn nil, errors.Errorf(\"type %q: expected SelectStmt, got %T\", typeStr, stmts[0].AST)\n\t}\n\tif sel.TargetList == nil || len(sel.TargetList.Items) != 1 {\n\t\treturn nil, errors.Errorf(\"type %q: expected 1 target\", typeStr)\n\t}\n\trt, ok := sel.TargetList.Items[0].(*ast.ResTarget)\n\tif !ok {\n\t\treturn nil, errors.Errorf(\"type %q: expected ResTarget, got %T\", typeStr, sel.TargetList.Items[0])\n\t}\n\tcast, ok := rt.Val.(*ast.TypeCast)\n\tif !ok {\n\t\treturn nil, errors.Errorf(\"type %q: expected TypeCast, got %T\", typeStr, rt.Val)\n\t}\n\treturn cast.TypeName, nil\n}\n\n// extractUserTypeRefs returns the user-defined type references embedded in a\n// PG type string. Built-in types, PG internal array forms (_name), and\n// system-schema-qualified types return nil.\n//\n// Soundness rule (hard contract C5): false negatives are acceptable (the\n// loader's pseudo fallback catches them); false positives are not, because\n// they invent edges in the dependency graph.\nfunc extractUserTypeRefs(typeStr string) []UserTypeRef {\n\tif typeStr == \"\" {\n\t\treturn nil\n\t}\n\tbase := stripTypeModifiers(typeStr)\n\tif base == \"\" || isBuiltinType(base) {\n\t\treturn nil","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/plugin/parser/pg/query_span_loader_type_name.go#L30-L66","documentation":"The ResTarget's value must be an *ast.TypeCast (the NULL::<type> cast) for typeNameFromString to extract the ast.TypeName. This error fires when the expression inside the sole target is not a cast, meaning the type string caused the probe query to parse into some other expression form. It is the last shape check before returning the TypeName, guarding the entire cast-extraction trick.","triggerScenarios":"rt.Val is not *ast.TypeCast — e.g. a type string containing operators or syntax that turns NULL::X into a different expression (such as a function call or A_Expr) — reached via buildCompositeTypeStmt, buildCreateStmt, buildCreateFunctionStmtFromSignature, or mustTypeName.","commonSituations":"Type strings with unusual syntax (e.g. interval qualifiers, array bounds expressions, or typos like \"int[]\" variants) that the PG parser rewrites into non-cast nodes; also parser version changes in node representation.","solutions":["Inspect the %T value in the error to see which expression node replaced the TypeCast","Normalize or reject the offending type string before it enters the loader","Extend the extractor to also unwrap the new node form if it legitimately encodes a type","Add the failing string to TestLoaderTypeNameFromString to verify the fix"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := typeNameFromString(typeStr); err != nil {\n    return fmt.Errorf(\"unsupported type syntax %q: %w\", typeStr, err)\n}","preventionTips":["Test exotic type strings (arrays, interval qualifiers, schemanified types) against the loader","Reject or normalize non-cast-producing syntax at the metadata ingestion boundary","Extend the extractor for new expression node forms instead of letting them fail at runtime"],"tags":["postgresql","parsing","type-cast","internal-invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}