API Delete throwing 400 error

We have created many projects on our Octopus server and now I am attempting to delete most of them using the API I am able to run GET against the API without any problems but when attempting a DELETE I am getting a 400 error.
Example from log - First one is when using the web interface and the second is from calling the API

2023-07-14	00:19:30	DELETE	/api/Spaces-1/projects/Projects-503	443	Marc+Offutt	xxx.xxx128.3	200	378

2023-07-14	00:23:26	GET	/api/Spaces-1/projectgroups/all	80	Marc+Offutt	xxx.xxx.12.16	200	12
2023-07-14	00:23:26	DELETE	/api/Spaces-1/projects/Projects-375	80	Marc+Offutt	xxx.xxx.12.16	400	114

Here is the Powershell I am attempting to run

$ErrorActionPreference = "Stop";

# Define working variables
$octopusURL = "http://<my server>"
$octopusAPIKey = "API-<my api>"
$header = @{ "X-Octopus-ApiKey" = $octopusAPIKey
             "accept" = "application/json" }
$spaceName = "default"
$omitProjectGroup = '8.2.4'
$omitProjectName = 'creds'
$omitProjectName2 = 'datadog'

# Get space
$space = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/spaces/all" -Headers $header) | Where-Object {$_.Name -eq $spaceName }
echo $space

# Get project
$projects = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/$($space.Id)/projects/all" -Headers $header)
#echo $projects


# Get projectGroups
$projectGroups = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/$($space.Id)/projectgroups/all" -Headers $header) | Where-Object {$_.Name -notmatch $omitProjectGroup } 
foreach ($projectGroup in $projectGroups){
    echo $projectGroup.Name
}

echo ""

$projects_new = $projects | Where-Object { (($_.Name -inotmatch $omitProjectName) -and ( $_.Name -inotmatch $omitProjectName2 ))-and ($projectGroups.Id -contains $_.ProjectGroupID  ) }


foreach ($project in $projects_new){
    echo $project.Name
}

# Delete project
foreach ($project in $projects_new){
    echo "$octopusURL/api/$($space.Id)/projects/$($project.Id)" 
    (Invoke-RestMethod -Method Delete -Uri "$octopusURL/api/$($space.Id)/projects/$($project.Id)" -Headers $header)
    echo $project.Name  ' - Deleted'
    break
}

We are on V2019.9.4 - yes, I realize it is old but the swagger page indicates this API is available.

Hi @marc.offutt,

Cheers for reaching out, I’ll dig into this and see if I can spot what’s going on with this 400 error!

I can see the failing request is over port 80 while the successful one was 443, does changing the URL to https:// allow for it to succeed?

Our docs give an example for looping over projects checking their deployment process which could be a good reference: Delete projects with no process | Documentation and Support

Looking forward to hearing how you get on, I’ll keep you posted with any further suggestions!

Best Regards,

The 443 request is from a different server using the web interface. I was running the script on the actual server that hosts Octopus and won’t run on 443 hence the port 80. I did also try it from the server where I was using the web interface over 443 and it returned the same results. The actual delete Invoke-RestMethod came directly out of the API documentation.

I appreciate any help you can give. I am getting all of the project names and they are filtering correctly it is just the DELETE

https://xxxxxx.xxxxx.xxxxx.com/api/Spaces-1/projects/Projects-375
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
At line:39 char:5

  • Invoke-RestMethod -Method Delete -Uri "$octopusURL/api/$($space.I ...
    
  • ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    • FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Hi @marc.offutt,

No problem at all, cheers for testing that!

I’ve was able to get your script it working on my end without making any changes to it so I can confirm it’s correct, however I was also getting a Bad Request when targeting an HTTP url while forcing HTTPS redirect: Expose the Octopus Web Portal over HTTPS | Documentation and Support

Once I removed that setting I was able to target the HTTP url ok, however if you don’t have this setting enable then it could be caused by the HSTS header being configured: Expose the Octopus Web Portal over HTTPS | Documentation and Support

I did also try it from the server where I was using the web interface over 443

Just to confirm, you tested running the script using the HTTPS url from the instance that succeeded through the UI? It seems strange that this would also cause a Bad Request, are there any proxies in-between?

I’d be happy to check over the Octopus.Server logs for any clues if you’d like to send them through to our Secure Upload Portal or answer any questions you have!

Best Regards,

I appreciate the help. I did go to the Octopus server itself and ran the Web UI from there and was able to also delete a project over port 80. We do not have the forced redirect checked nor do we have HSTS enabled

I uploaded some logs. You will notice there are two different users, I changed API keys just to see if it would make a difference. Looking at the web bindings I also noticed that localhost was being used. I attempted to use that, but received the same resiults.

Hi @marc.offutt,

Cheers for confirming that and providing the logs, is it just for the one project that you are seeing this error? Projects-375

If you try to delete it through the UI does it show the same error? I thought I recalled an old issue with deleting cloned projects but I haven’t been able to locate it, could you please send through the JSON returned for Projects-375 endpoint?

I’ll keep you posted with any other suggestions, looking forward to hearing how you get on!

Best Regards,

Sorry, got pulled away to something else. Here you go

Id                              : Projects-375
VariableSetId                   : variableset-Projects-375
DeploymentProcessId             : deploymentprocess-Projects-375
ClonedFromProjectId             : Projects-342
DiscreteChannelRelease          : False
IncludedLibraryVariableSetIds   : {}
DefaultToSkipIfAlreadyInstalled : False
TenantedDeploymentMode          : Untenanted
DefaultGuidedFailureMode        : EnvironmentDefault
VersioningStrategy              : @{Template=#{Octopus.Version.LastMajor}.#{Octopus.Version.LastMinor}.#{Octopus.Version.NextPatch}; DonorPackage=; 
                                  DonorPackageStepId=}
ReleaseCreationStrategy         : @{ChannelId=; ReleaseCreationPackage=; ReleaseCreationPackageStepId=}
Templates                       : {}
AutoDeployReleaseOverrides      : {}
ReleaseNotesTemplate            : 
SpaceId                         : Spaces-1
ExtensionSettings               : {}
Name                            : Activation Policy & Tenant Installer
Slug                            : activation-policy-tenant-installer
Description                     : Add additional activation policies and build tenant installers for existing tenants
IsDisabled                      : False
ProjectGroupId                  : ProjectGroups-143
LifecycleId                     : Lifecycles-5
AutoCreateRelease               : False
ProjectConnectivityPolicy       : @{SkipMachineBehavior=None; TargetRoles=System.Object[]; AllowDeploymentsToNoTargets=False; ExcludeUnhealthyTargets=False}
Links                           : @{Self=/api/Spaces-1/projects/Projects-375; 
                                  Releases=/api/Spaces-1/projects/Projects-375/releases{/version}{?skip,take,searchByVersion}; 
                                  Channels=/api/Spaces-1/projects/Projects-375/channels{?skip,take,partialName}; 
                                  Triggers=/api/Spaces-1/projects/Projects-375/triggers{?skip,take,partialName,triggerActionType}; 
                                  ScheduledTriggers=/api/Spaces-1/projects/Projects-375/scheduledtriggers{?skip,take,partialName}; 
                                  OrderChannels=/api/Spaces-1/projects/Projects-375/channels/order; 
                                  Variables=/api/Spaces-1/variables/variableset-Projects-375; 
                                  Progression=/api/Spaces-1/progression/Projects-375{?aggregate}; 
                                  DeploymentProcess=/api/Spaces-1/deploymentprocesses/deploymentprocess-Projects-375; 
                                  Web=/app#/Spaces-1/projects/Projects-375; Logo=/api/Spaces-1/projects/Projects-375/logo?cb=2019.9.4; 
                                  Metadata=/api/Spaces-1/projects/Projects-375/metadata}

Hi @marc.offutt,

No worries at all, cheers for sending that JSON through!

It looks like the Versioning Strategy isn’t quite right, specifically the DonorPackageStepId being present but empty:

@{Template=#{Octopus.Version.LastMajor}.#{Octopus.Version.LastMinor}.#{Octopus.Version.NextPatch}; DonorPackage=; 
                                  DonorPackageStepId=}

If you navigate in the UI to the Project’s Deployment Settings, are you able to change the release versioning to use a template or specify a step and package to use instead?

Hopefully that should allow for it to be deleted without needing to modify the DB directly, feel free to reach out with any questions at all!

Best Regards,

Thank you for the reply
I can, but having to do this will not help. If I have to do this with every project I mine as well just go in and delete them by hand which is what I’m attempting to avoid by using the API in the first place. That versioning strategy is just the default as we don’t use it.

Hi @marc.offutt,

No problem at all, sorry I assumed it was just the single project!

The expected value for the Versioning Strategy using the default template should look like the following, which has an empty DonorPackage value, but not DonorPackageStepId which I think is causing the bad request:

@{Template=#{Octopus.Version.LastMajor}.#{Octopus.Version.LastMinor}.#{Octopus.Version.NextPatch}; DonorPackage=}

I’ll put a script together for modifying projects to use the default json above however you might want to look into how these projects are being created with DonorPackageStepId so it can prevent it from being an issue in future.

Best Regards,

Hi @marc.offutt,

Ahh sorry look like I was incorrect and 2019 works a bit differently with the DonorPackageStepId being included back then.

I’ll keep digging into this and see if I can spot what’s really causing the issue, I have a feeling it might be the clonedProject being referenced, has Projects-342 been removed already?

I’ll keep you posted with any updates on my end or if I have questions, feel free to do the same!

Well I think you are on to something. I switched out the filter to return just project 342 and it returned. but in the process it also deleted it (I didn’t comment out the delete). So now I wonder if it is just the first project causing the script to fail. I may filter out 375 and see if it works. I will let you know. For reference purposes this was the info for 342 before it was deleted:

Id                              : Projects-342
VariableSetId                   : variableset-Projects-342
DeploymentProcessId             : deploymentprocess-Projects-342
ClonedFromProjectId             : Projects-86
DiscreteChannelRelease          : False
IncludedLibraryVariableSetIds   : {}
DefaultToSkipIfAlreadyInstalled : False
TenantedDeploymentMode          : Untenanted
DefaultGuidedFailureMode        : EnvironmentDefault
VersioningStrategy              : @{Template=#{Octopus.Version.LastMajor}.#{Octopus.Version.LastMinor}.#{Octopus.Version.NextPatch}; DonorPackage=; 
                                  DonorPackageStepId=}
ReleaseCreationStrategy         : @{ChannelId=; ReleaseCreationPackage=; ReleaseCreationPackageStepId=}
Templates                       : {}
AutoDeployReleaseOverrides      : {}
ReleaseNotesTemplate            : 
SpaceId                         : Spaces-1
ExtensionSettings               : {}
Name                            : Tenant Provisioning
Slug                            : tenant-provisioning
Description                     : Preprod and Prod deployments supporting blue/green architecture
IsDisabled                      : False
ProjectGroupId                  : ProjectGroups-143
LifecycleId                     : Lifecycles-5
AutoCreateRelease               : False
ProjectConnectivityPolicy       : @{SkipMachineBehavior=None; TargetRoles=System.Object[]; AllowDeploymentsToNoTargets=False; ExcludeUnhealthyTargets=False}
Links                           : @{Self=/api/Spaces-1/projects/Projects-342; 
                                  Releases=/api/Spaces-1/projects/Projects-342/releases{/version}{?skip,take,searchByVersion}; 
                                  Channels=/api/Spaces-1/projects/Projects-342/channels{?skip,take,partialName}; 
                                  Triggers=/api/Spaces-1/projects/Projects-342/triggers{?skip,take,partialName,triggerActionType}; 
                                  ScheduledTriggers=/api/Spaces-1/projects/Projects-342/scheduledtriggers{?skip,take,partialName}; 
                                  OrderChannels=/api/Spaces-1/projects/Projects-342/channels/order; 
                                  Variables=/api/Spaces-1/variables/variableset-Projects-342; 
                                  Progression=/api/Spaces-1/progression/Projects-342{?aggregate}; 
                                  DeploymentProcess=/api/Spaces-1/deploymentprocesses/deploymentprocess-Projects-342; 
                                  Web=/app#/Spaces-1/projects/Projects-342; Logo=/api/Spaces-1/projects/Projects-342/logo?cb=2019.9.4; 
                                  Metadata=/api/Spaces-1/projects/Projects-342/metadata}

So one of the projects cannot be deleted from the UI because of the following, so this may be what was keeping it from being able to be deleted.

That looks to have been it. I removed the permissions and was able to delete through the UI. There were only a couple of projects left so I did those manually.

I appreciate all the help.

1 Like

This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.