{"record":{"id":"917ea2742cc93bf0","repo":"apache/beam","slug":"panic-err-gcs","errorCode":null,"errorMessage":"panic(err)","messagePattern":"panic\\(err\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/util/gcsx/gcs.go","lineNumber":160,"sourceCode":"\t\treturn \"\", \"\", errors.Errorf(\"object %s must have 'gs' scheme\", object)\n\t}\n\tif parsed.Host == \"\" {\n\t\treturn \"\", \"\", errors.Errorf(\"object %s must have bucket\", object)\n\t}\n\tif parsed.Path == \"\" {\n\t\treturn parsed.Host, \"\", nil\n\t}\n\n\t// remove leading \"/\" in URL path\n\treturn parsed.Host, parsed.Path[1:], nil\n}\n\n// Join joins a GCS path with an element. Preserves\n// the gs:// prefix.\nfunc Join(object string, elms ...string) string {\n\tbucket, prefix, err := ParseObject(object)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn MakeObject(bucket, path.Join(prefix, path.Join(elms...)))\n}\n","sourceCodeStart":142,"sourceCodeEnd":164,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/util/gcsx/gcs.go#L142-L164","documentation":"Join parses a gs:// object path and appends path elements, preserving the prefix; if ParseObject fails (the object is not a valid gs:// path) Join panics with the parse error. It treats an invalid GCS URL as an unrecoverable construction mistake.","triggerScenarios":"Calling gcsx.Join with a string that lacks the gs:// prefix or has no bucket (e.g. Join(\"s3://x/y\", \"a\"), Join(\"\", \"log.txt\"), Join(\"plain/path\", \"a\")) — ParseObject returns an error and Join panics.","commonSituations":"Users passing AWS S3 or local filesystem paths to a Beam GCS utility; a bucket variable defaulting to empty; stripping the gs:// prefix upstream and passing the remainder to Join.","solutions":["Pass a well-formed gs://bucket/path string to Join (or MakeObject output)","Validate the path with ParseObject first and handle its error instead of panicking","If non-GCS paths are possible, branch on prefix before calling Join","Normalize the path (prepend \"gs://\" + bucket) when the prefix may have been stripped"],"exampleFix":"// before\nout := gcsx.Join(gcsPath, \"results\") // panics if gcsPath invalid\n// after\nif _, _, err := gcsx.ParseObject(gcsPath); err != nil {\n\treturn fmt.Errorf(\"invalid GCS path %q: %w\", gcsPath, err)\n}\nout := gcsx.Join(gcsPath, \"results\")","handlingStrategy":"validation","validationCode":"if !strings.HasPrefix(object, \"gs://\") {\n\treturn fmt.Errorf(\"expected gs:// path, got %q\", object)\n}","typeGuard":"func isGCSPath(s string) bool { _, _, err := gcsx.ParseObject(s); return err == nil }","tryCatchPattern":"defer func() {\n\tif r := recover(); r != nil {\n\t\terr = fmt.Errorf(\"invalid GCS object %q: %v\", object, r)\n\t}\n}()","preventionTips":["Only pass MakeObject/ParseObject-produced strings into gcsx.Join","Route non-GCS paths (s3://, local) through the appropriate filesystem helper","Normalize stripped prefixes back to gs:// before joining"],"tags":["go","gcs","panic","url"],"backgroundTag":"invalid-url-format","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}