> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuneplane.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Remove Node

> Remove a Node. Refused while it is active unless forced.

The refusal is the useful part: an active Node is one the scheduler is still
placing work on, and removing its identity is what makes a running container
unreconcilable. Draining first is the answer; `force` is for a machine that
is already gone.

**Allowed on an externally managed Fleet, unlike drain and cordon**, and the
asymmetry is the point. Those two are placement policy applied to a machine
somebody else's scheduler owns, which this platform has no business
asserting. This one deletes a row *this platform* wrote -- and a database
that predates the kind restriction can hold rows nothing will ever honour,
which are hidden from `/nodes` and ignored for placement precisely because
they are meaningless. Refusing here too would leave an administrator with
records they can see in the diagnostic, cannot act on, and cannot get rid
of: the platform's own mess, with the cleanup door locked.



## OpenAPI

````yaml /api-reference/openapi.json delete /api/fleets/{fleet_id}/nodes/{node_id}
openapi: 3.1.0
info:
  title: TunePlane Console
  description: >-
    The TunePlane control plane. Everything the `tuneplane` CLI and the web
    console do goes through this API, and so can your own tooling.


    Authenticate with a bearer token from `POST /api/auth/login` or a CLI device
    flow; see the Authentication page for how to get one and how long it lasts.
  version: 0.3.42
servers:
  - url: https://{host}
    description: Your TunePlane deployment
    variables:
      host:
        default: tuneplane.your-company.com
        description: >-
          The domain your administrator gave you, without a scheme or trailing
          slash.
security: []
tags:
  - name: auth
    description: >-
      Log in, exchange a CLI device code, and inspect the current identity.
      Everything else on this API needs a bearer token from here.
  - name: profile
    description: >-
      The signed-in user's own account: quota, tokens, preferences, and
      notification settings.
  - name: projects
    description: >-
      Projects group runs the way `tuneplane.yaml` names them. A run belongs to
      exactly one.
  - name: experiments
    description: >-
      Read the experiment definitions the console found in the configured
      repository.
  - name: submit
    description: >-
      Admit a JobSpec. This is what `tp submit` calls: the catalog handshake,
      quota check, and preflight all happen here, and a rejection names the gate
      that refused it.
  - name: jobs
    description: >-
      Everything about a job after it is admitted: status, logs, metrics,
      samples, artifacts, and the pause/resume/stop controls.
  - name: runs
    description: >-
      Finished work, addressed by run id. A run outlives the job that produced
      it.
  - name: ingest
    description: >-
      The endpoints training code reports to. `tuneplane.report` speaks this;
      you only call it directly when writing an adapter for a framework the
      catalog does not cover.
  - name: datasets
    description: >-
      Versioned dataset upload, listing, and metadata. Protected datasets expose
      identity and schema here but never their records.
  - name: volumes
    description: Governed directories of files a job may mount read-only.
  - name: environments
    description: >-
      Agent RL environments: their manifests, versions, and upload URLs. A
      taskset is never returned.
  - name: benchmarks
    description: >-
      The benchmark catalog, the score matrix across runs, and externally scored
      evaluations.
  - name: rubrics
    description: >-
      Written scoring standards, their revisions, and which runs cited which
      version.
  - name: judge
    description: >-
      The LLM-judge endpoint a training job calls to score a rollout.
      OpenAI-compatible.
  - name: models
    description: >-
      The model registry: register a version, promote it, archive it, read its
      card.
  - name: model-deployments
    description: >-
      Managed model versions serving application traffic: revisions, promotion,
      rollback, suspension, and deployment tokens.
  - name: inference
    description: >-
      OpenAI-compatible inference against a promoted deployment revision. This
      is the endpoint applications call.
  - name: playground
    description: >-
      Short-lived serving sessions for human evaluation. Distinct from a
      deployment: a session expires, a deployment does not.
  - name: reflow
    description: >-
      The governed path from a deployment's production traffic back to the
      training data of its next version.
  - name: annotate
    description: 'Preference annotation: pull a batch, push judgements, read progress.'
  - name: plugins
    description: Installed plugins and the extension shelf the console renders.
  - name: diagnosis
    description: >-
      Automated analysis of a finished or failed run, and the accumulated
      project memory it draws on.
  - name: approvals
    description: 'Approval requests: an escalation path, one level deep, with a record.'
  - name: billing
    description: >-
      What the GPU-hours cost. One price on top of the hours the usage page
      already shows.
  - name: teams
    description: 'Teams: the unit capacity is budgeted to. A department, not a tenant.'
  - name: agent
    description: >-
      Submit plans: a proposed submission a human approves or rejects before it
      becomes a job.
  - name: share
    description: >-
      Public, revocable read-only links to a job or a comparison. The
      `/api/share/{token}` routes need no bearer token, which is the point.
  - name: notifications
    description: The signed-in user's notification feed.
  - name: search
    description: Cross-surface search over jobs, runs, datasets, and models.
  - name: sandbox
    description: >-
      Execute model-generated code in a throwaway container with no GPU and no
      network.
  - name: uploads
    description: >-
      Resumable upload sessions used by dataset, environment, and plugin
      publishing.
  - name: integrations-hf
    description: Hugging Face account linking and repository push.
  - name: mcp
    description: Model Context Protocol access information and per-user tool settings.
  - name: mcp-oauth
    description: >-
      OAuth metadata, authorization, token exchange, and dynamic client
      registration for MCP clients.
  - name: cluster
    description: Live capacity and node state across the fleets.
  - name: fleets
    description: >-
      Registered execution backends and the machines in them. Reading is open to
      every user; creating a fleet, minting a join token and draining a node are
      admin-only. Joining is authorized by the join token alone.
  - name: admin
    description: >-
      User, role, quota, hardware, schedule, integration, and settings
      administration. Admin role required.
  - name: tasks
    description: >-
      Scheduled platform maintenance tasks: what they are, when they last ran,
      and running one now.
  - name: report
    description: The rendered daily report page.
  - name: health
    description: Liveness and version. Unauthenticated.
paths:
  /api/fleets/{fleet_id}/nodes/{node_id}:
    delete:
      tags:
        - fleets
      summary: Remove Node
      description: >-
        Remove a Node. Refused while it is active unless forced.


        The refusal is the useful part: an active Node is one the scheduler is
        still

        placing work on, and removing its identity is what makes a running
        container

        unreconcilable. Draining first is the answer; `force` is for a machine
        that

        is already gone.


        **Allowed on an externally managed Fleet, unlike drain and cordon**, and
        the

        asymmetry is the point. Those two are placement policy applied to a
        machine

        somebody else's scheduler owns, which this platform has no business

        asserting. This one deletes a row *this platform* wrote -- and a
        database

        that predates the kind restriction can hold rows nothing will ever
        honour,

        which are hidden from `/nodes` and ignored for placement precisely
        because

        they are meaningless. Refusing here too would leave an administrator
        with

        records they can see in the diagnostic, cannot act on, and cannot get
        rid

        of: the platform's own mess, with the cleanup door locked.
      operationId: remove_node_api_fleets__fleet_id__nodes__node_id__delete
      parameters:
        - name: fleet_id
          in: path
          required: true
          schema:
            type: string
            title: Fleet Id
        - name: node_id
          in: path
          required: true
          schema:
            type: string
            title: Node Id
        - name: force
          in: query
          required: false
          schema:
            type: boolean
            title: Force
            default: false
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
        - HTTPBearer: []
components:
  schemas:
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer

````