{"record":{"id":"4941e069e562839f","repo":"google/tsunami-security-scanner","slug":"malformed-gcs-url-s","errorCode":null,"errorMessage":"Malformed GCS URL: '%s'","messagePattern":"Malformed GCS URL: '(.+?)'","errorType":"validation","errorClass":"ParameterException","httpStatus":null,"severity":"error","filePath":"main/src/main/java/com/google/tsunami/main/cli/ScanResultsArchiver.java","lineNumber":73,"sourceCode":"        description = \"The GCS file url for the uploaded scanning results.\")\n    public String gcsOutputFileUrl;\n\n    @Parameter(\n        names = \"--scan-results-gcs-output-format\",\n        description = \"The format of the scanning results uploaded to GCS bucket.\")\n    public OutputDataFormat gcsOutputFormat;\n\n    @Parameter(\n        names = \"--scan-results-logging-enabled\",\n        description = \"Enable logging of the scan results.\",\n        arity = 1)\n    public Boolean loggingEnabled = false;\n\n    @Override\n    public void validate() {\n      if (!Strings.isNullOrEmpty(gcsOutputFileUrl)\n          && !GS_URL_PATTERN.matcher(gcsOutputFileUrl).matches()) {\n        throw new ParameterException(String.format(\"Malformed GCS URL: '%s'\", gcsOutputFileUrl));\n      }\n    }\n  }\n\n  private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();\n\n  private final Options options;\n  private final RawFileArchiver rawFileArchiver;\n  private final GoogleCloudStorageArchiver.Factory googleCloudStorageArchiverFactory;\n\n  @Inject\n  // TODO(b/145315535): inject archivers using multibinder instead.\n  ScanResultsArchiver(\n      Options options,\n      RawFileArchiver rawFileArchiver,\n      GoogleCloudStorageArchiver.Factory googleCloudStorageArchiverFactory) {\n    this.options = checkNotNull(options);\n    this.rawFileArchiver = checkNotNull(rawFileArchiver);","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/google/tsunami-security-scanner/blob/363ba87b3543f8ae8e4304d3416818f03da7f262/main/src/main/java/com/google/tsunami/main/cli/ScanResultsArchiver.java#L55-L91","documentation":"ScanResultsArchiver.Options.validate() throws a picocli ParameterException when --gcs-output-file-url is set but does not match the expected Google Cloud Storage URL regex (GS_URL_PATTERN, e.g. gs://bucket/path). It guards against mistyped output destinations before the scan results archiving step runs.","triggerScenarios":"Passing --gcs-output-file-url with a value like 'https://storage.googleapis.com/...' or 'gs:/bucket/x' that does not fully match GS_URL_PATTERN, checked in validate() at ScanResultsArchiver.java:73.","commonSituations":"Using an HTTP URL to a GCS object instead of the gs:// URI scheme; missing the bucket; extra whitespace; typos like 'gcs://' or a single slash after the scheme.","solutions":["Use the canonical form gs://<bucket>/<object-path> for --gcs-output-file-url.","Remove surrounding whitespace or stray characters from the flag value.","If you want local output instead, drop the GCS flag and use the local output directory option."],"exampleFix":"// before\n--gcs-output-file-url=https://storage.googleapis.com/my-bucket/results.json\n// after\n--gcs-output-file-url=gs://my-bucket/results.json","handlingStrategy":"validation","validationCode":"boolean ok = gcsUrl != null && !gcsUrl.isBlank() && gcsUrl.matches(\"^gs://[^/]+/.+\");","typeGuard":null,"tryCatchPattern":"try { archiverOptions.validate(); } catch (ParameterException e) { System.err.println(\"Fix --gcs-output-file-url: \" + e.getMessage()); }","preventionTips":["Always use gs://bucket/object form for GCS outputs.","Trim whitespace from flag values in wrapper scripts.","Validate the URL in CI before running the scan."],"tags":["cli","gcs","url-validation","java"],"backgroundTag":"invalid-url-format","analyzedSha":"363ba87b3543f8ae8e4304d3416818f03da7f262","analyzedAt":"2026-09-13T01:50:53.990Z","contentChangedAt":"2026-09-13T01:50:53.990Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}