---
url: /en/faq.md
description: >-
  Answers frequently asked questions about CNB pipelines, covering trigger and
  configuration, execution and debugging, caching and environment, and common
  troubleshooting scenarios.
---
Before submitting feedback,
check the corresponding documentation or the following FAQs and [feedback](https://cnb.build/cnb/feedback).

If you cannot find the answer, submit an `issue` at [feedback](https://cnb.build/cnb/feedback).

## Trigger & Configuration

### Why is the pipeline not triggered?

To diagnose why a pipeline is not triggered, first understand the process from trigger to execution.

Taking the `push` event as an example:

```mermaid
flowchart LR
    push(git push) --> config(CI reads .cnb.yml from corresponding branch) --> event(Gets push event configuration for the branch) --> skip(skip detection) --> Pipeline-execution(Pipeline execution)
```

> The `skip detection` includes `ifNewBranch` and `ifModify`.
> Please refer to [syntax](./build/grammar.md#Pipeline-ifModify).

You can then trace through this process step by step:

1. Is the code pushed to the remote repository?
2. Does the corresponding branch have `.cnb.yml`?
   1. Do the included files have permission?
   2. Are there any format or syntax issues in the configuration content?
3. Does the `.cnb.yml` declare the `push` event pipeline for the current branch?
4. Did you hit the skip detection?

> The default branch in CNB is usually `main`.
> Some repositories migrated from other platforms may have `master` as the default branch. Please note the difference.

### Why doesn't the pipeline configured on one branch work for another branch?

Pipeline configurations in `.cnb.yml` **only apply to the current branch**.
Configuring a pipeline for branch B under branch A will not make branch B execute according to that configuration.
The actual execution depends on each branch's own `.cnb.yml`.

For example, if you write a `dev` push configuration in the `main` branch's `.cnb.yml`,
when the `dev` branch is pushed, the system reads the `dev` branch's own `.cnb.yml`, not the one from `main`.

For details, refer to [Trigger Branch](./build/trigger-rule.md#trigger-branch).

### Why doesn't a forked repository trigger pipelines automatically?

For security reasons,
**forked repositories do not automatically trigger pipelines by default** (including Git operation events,
scheduled task events, and Issue events).

To enable this, go to the **source repository** page, navigate to **Settings → Cloud Native Build**,
and check "Allow forked repositories to trigger automatically by default".

> Note: Even with auto-trigger enabled,
> the `CNB_TOKEN` permissions in forked repository pipelines are restricted to the current repository scope only.

For details,
refer to [Fork Repository Trigger Restrictions](./build/trigger-rule.md#fork-repository-trigger-restrictions).

### How to skip pipeline execution?

For `push`, `commit.add`, and `branch.create` events, you can skip pipeline execution in two ways:

1. Add `[ci skip]` or `[skip ci]` to the commit message:

```bash
git commit -m "docs: update readme [ci skip]"
git push origin main
```

2. Use a git push option:

```bash
git push origin main -o ci.skip
```

For details, refer to [Skip Pipeline](./build/skip-pipeline.md).

### Why can't plugin tasks access environment variables set via env / imports?

This is one of the key differences between script tasks and plugin tasks.
**Plugin tasks do not receive custom environment variables declared via `env` or `imports`** — they can only use CNB's
built-in system environment variables.

Plugin task parameters should be passed via `settings`:

```yaml title=".cnb.yml"
# ❌ Wrong: variables declared in env won't be passed to the plugin
- name: wrong
  image: plugins/npm
  env:
    PLUGIN_USERNAME: $NPM_USER

# ✅ Correct: pass parameters via settings
- name: correct
  image: plugins/npm
  settings:
    username: $NPM_USER
```

For a detailed comparison, refer to [Script Tasks vs Plugin Tasks](./build/script-vs-plugin.md).

## Execution & Debugging

### Works locally but fails in CI?

To locate this issue, first understand the differences between the local and CI environments:

|       | Local                         | CI Environment                |
| ----- | ---------------------------- | ---------------------- |
| Network | Local network (e.g., office intranet) | CI machine's network |
| Files | All files in the local directory | Code of the corresponding branch in the Git repository |
| Environment | Native | Specified Docker container environment |
| Shell | Local shell | sh |

Understanding these differences, you can troubleshoot in sequence:

1. Are there any uncommitted files?
2. Are the files required for build caught by `.gitignore`?
3. Are you dependent on local-only resources (such as local APIs, credentials, etc.)?
4. Does the [cpus](./build/grammar.md#runner) declared in CI meet the requirements?
5. Run the same image locally to get the same build environment as CI for debugging.

The default image for `Cloud Native Build` is [\_\_ENV\_\_CNB\_DEFAULT\_DOCKER\_IMAGE](https://cnb.cool/cnb/cool/default-build-env).

You can execute the following command to enter the default CI environment for debugging:

```bash
docker run --rm -it -v $(pwd):$(pwd) -w $(pwd) cnbcool/default-build-env sh
```

If you have declared another image as the pipeline build environment,
replace `cnbcool/default-build-env` in the command above with the corresponding image address.

### How to log in to the pipeline container for debugging?

Please refer to [Login Debug](./build/login-debug.md).

### Pipeline execution script results differ from login debug?

The default shell in the pipeline is `sh`, while login debugging uses `bash`.
There are syntax differences between the two.

If you confirm that the pipeline container supports `bash` (the default container does, but custom containers may not),
you can change the execution script to:

```bash
bash xxx.sh
# or
bash -c 'original statement'
```

### Pipeline times out with no output?

A Job with no log output for more than 10 minutes will be terminated.
Consider adding more log output — for `npm install`, you can add the `--verbose` parameter.

This is different from the Job's `timeout` setting and cannot be changed through configuration.

### Why does docker push / git push fail in PR pipelines?

PR-related events are [untrusted events](./build/trigger-rule.md#untrusted-events).
The `CNB_TOKEN` permissions in the pipeline are restricted — code and artifact registry have **read-only** access,
so write operations like `docker push` and `git push` will fail.

This is a security measure: PR source branch code may be modified by unauthorized users.
Granting write permissions could lead to malicious code injection or build artifact tampering.

**Solution**: Move tasks involving push operations to trusted events such as `push`, `pull_request.target`,
or `tag_push`.

### Why can't a public repository pipeline access private resources?

If the pipeline runs in a public repository, the `CNB_TOKEN` in the pipeline can only access **public resources**.
It cannot access private resources such as private code repositories or private artifact registries.

This prevents pipeline code in public repositories from gaining access to private resources.

To access private resources, you can choose one of the following options:

1. Trigger the pipeline in a private repository.
2. Adjust the target resource access scope.
3. Create a personal token or deploy token with the required permissions and use it in the pipeline.

For details, refer to [CNB\_TOKEN Security Restrictions](./build/build-in-env.md#security-restrictions).

### Why does the pipeline fail when I haven't changed any code?

Check if dependent resources have changed:

1. Does the plugin task use `latest` as the image version, and has the image changed?
2. Have the referenced files from other repositories changed?
3. Possible network fluctuation. Try rebuilding.

### How to view the complete pipeline logs?

The CI service sends plugin and script tasks to the Runner for execution. If task logs are too long,
they will be truncated.

A stage summarizes logs of all its tasks. If stage logs are too long,
they will also be truncated for better display on the log page.

After the build completes,
click the log download button in the top right corner of the pipeline on the log page to view the complete logs.

## Caching & Environment

### Why does caching (volumes) sometimes not work?

Pipeline file caching (`volumes`) is **node-level** — caches are stored on the local disk of the build node.
By default, each repository's pipelines are assigned to a fixed set of 3 nodes, so:

1. **Not shared across nodes**: If the last build wrote cache on node A, but this build is assigned to node B,
   the cache will not be available.
2. **Nodes may change**: As the platform scales up or down, the assigned nodes may change,
   and caches on old nodes are not automatically migrated.

If you need the same cache for every build,
you can use the [docker:cache](./build/internal-steps/README.md#docker-cache)
built-in task to build the cache as a Docker image, enabling cross-node caching.

For details, refer to [Pipeline Cache](./build/pipeline-cache.md).

### Why doesn't CNB provide a fixed exit IP?

CNB's exit IP is dynamic and may change over time.

Reasons:

1. **Operations Elasticity**: The platform automatically scales, migrates nodes,
   and performs other operations based on load. The exit IP changes dynamically.
2. **Security Recommendation**: We do not recommend whitelisting CNB's exit IP. CNB is a public platform,
   and whitelisting its exit IP is equivalent to whitelisting the entire public internet, which poses security risks.

Alternative solutions (when you need a fixed IP to access internal services):

* **Private Proxy**: Configure your own proxy server and route requests through it using the proxy's fixed IP
* **Jump Server**: Connect to the target machine via SSH jump server to execute commands,
  using the [cnbcool/ssh](https://cnb.cool/cnb/plugins/cnbcool/ssh) plugin.
  [Reference example](https://cnb.cool/examples/ecosystem/springboot-maven-docker-jumpserver)
* **Tencent Cloud Plugin**: The [tencentcom/tcloud-cmd](https://cnb.cool/cnb/plugins/tencentcom/tcloud-cmd)
  plugin for remote command execution without whitelist configuration

### How to build multi-architecture/multi-platform images?

If you need to use `buildx` to build images for multiple architectures/platforms,
you can enable the `rootlessBuildkitd` feature. You need to declare it in the service:

```yaml title=".cnb.yml"
main:
  push:
    - docker:
        image: golang:1.24
      services:
        - name: docker
          options:
            rootlessBuildkitd:
              enabled: true
      env:
        IMAGE_TAG: ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest
      stages:
        - name: go build
          script: ./build.sh
        - name: docker login
          script: docker login -u ${CNB_TOKEN_USER_NAME} -p "${CNB_TOKEN}" ${CNB_DOCKER_REGISTRY}
        - name: docker build and push
          script: docker buildx build -t ${IMAGE_TAG} --platform linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/loong64,linux/arm/v7,linux/arm/v6 --push .
```

### Docker image fails with UID/GID exceeding 65535 in pipeline?

If you encounter an error like this when running a Docker image in your pipeline:

```text
docker: failed to extract layer ... failed to Lchown ... for UID 100000, GID 100000: lchown ...: invalid argument
(Hint: try increasing the number of subordinate IDs in /etc/subuid and /etc/subgid)
```

**Cause:**

Docker on CNB uses `uidmap` technology, which restricts the UID range inside containers to 0-65535.
When an image contains files with UID/GID exceeding 65535, Docker cannot properly map them,
causing image layer extraction to fail.

**Solution:**

Rebuild the image by cleaning up such files or changing them to normal UID/GID values.
Avoid using base images with UID/GID exceeding 65535.

### Why is the repository storage usage in the pipeline inconsistent with what's shown on the page?

The repository size seen in the pipeline is usually close to what is displayed on the page.

However, for all public `forked repositories`, to speed up builds and optimize storage,
all forked repositories on build nodes reuse the `.git` directory of their ancestor repository,
then use `OverlayFS` to split into multiple copies. Therefore,
the repository size seen in the pipeline actually includes the ancestor and all descendant repositories.

For regular repositories, after triggering GC on the page,
the repository size in the pipeline will not change immediately.
You need to wait for the build machine's cache GC logic to run before it matches the page display.

## Code Repository

### How to resolve code merge conflicts? {#dai-ma-he-bing-chong-tu}

If you encounter code conflicts when creating a PR or in PR-related event builds,
you can resolve them with the following commands:

```bash
git fetch origin          # Get updates from the remote repository
git rebase -i origin/main # Actual target branch name

# Handle conflicts locally
git commit  # Commit to local repository based on actual situation
git push -f # Push to remote repository
```

### How to completely delete files from a Git repository and free up space?

Git repositories support recovery of any historical commits. The `.git` directory stores all historical files.
Simply deleting files from the working directory does not free up space.

To completely delete files from a Git repository and free up space, you can use the following two methods:

**Method 1** (simplest): Create a new repository on the remote, copy the files you need,
then rename it to the original name.

**Method 2** (more complex): Use `git filter-branch` or third-party tools (e.g., `BFG Repo-Cleaner`)
to completely delete files locally, force push to the remote, then trigger the remote repository GC process.
