OpenGL ES 3.1 not working Separate Shader Program

Android Studio, NDK 26.1.10909125, SDK 34 (Android 14), C++17. Game Activity (C++) template project. From template only context creation (change version to 3.1). I wrote the rest of the code myself (rewrite, from PC version 4.6).
If I use standard way for shaders then all work fine. But if use separate shaders with pipeline then triangle only black. To start, I simply draw a triangle.
vertex shader

#version 310 es

layout (location = 0) in vec3 pos;

void main() {
    gl_Position = vec4(pos, 1.0f);
}

fragment shader

#version 310 es

layout (location = 0) out mediump vec4 color;

void main(){
    color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}

Error checking code is silent in logs

glValidateProgram(id);
    int s{};
    glGetProgramiv(id, GL_VALIDATE_STATUS, &s);
    if (s == GL_FALSE) {
        int size{};
        glGetProgramiv(id, GL_INFO_LOG_LENGTH, &size);
        GLsizei sz{};
        char* c{ new char[size] };
        glGetProgramInfoLog(id, size, &sz, c);
        aout << size << " " <<  sz << std::endl;
        std::string err{c};
        aout <<  "Error validating shader program: " << err << std::endl;
        delete[] c;
    }

//pipeline check
    glValidateProgramPipeline(id);
    int s{};
    glGetProgramPipelineiv(id, GL_VALIDATE_STATUS, &s);
    if (s == GL_FALSE) {
        int size{};
        glGetProgramPipelineiv(id, GL_INFO_LOG_LENGTH, &size);
        GLsizei sz{};
        char* c = new char[size] {};
        glGetProgramPipelineInfoLog(id, size, &sz, c);
        std::string err{ c };
        delete[] c;
        aout <<  "Error validating pipeline: " << err << std::endl;
    }

It’s also interesting why error checks work fine on a PC, but on Android the error text is not displayed, that is, the message size is 0. Only the fact of the presence of the error itself when it is present.

On PC separate shaders work only with explicity in vertex

#version 460 core

out gl_PerVertex { 
    vec4 gl_Position; 
};

but in ES give errors
trying

out highp vec4 gl_Position;

It compiles without errors, but the result is the same. If you do not bind a pipeline, the triangle is drawn the same way, without color (black, but in fragment must be red).

some pseudocode

//creation
char* vertsrc = ...;
char* fragsrc = ...;
unsigned vertex = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertsrc);
//validate shader
unsigned fragment = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragsrc);
//validate shader
unsigned pipeline = 0;
glGenProgramPipelines(1, &pipeline);
glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT, vertex);
glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, fragment);
//validate pipeline

//in draw
glBindProgramPipeline(pipeline);
//bind vao, draw call
glBindProgramPipeline(0);

I study the specifications OpenGL ES and GLSL for 3.1 and find nothing interesting or wrong.